C/C++中相同的浮點數的內存布局一定是一樣嗎?

C/C++中相同的浮點數的內存布局一定是一樣嗎?

比如

float a = 1.0;
float b = 1.0

那麼a和b的內存布局(memcpy)一定是一樣的嗎?

如果不一定樣,那會在什麼情況下出現不一樣的情況呢?


題目似乎改過,我回答一下,浮點數中,相同的值是否都有同一個內存表示。

IEEE754中,浮點數可表示的值可分類成 ±0、normal、subnormal、±∞、NaN。前4類的表示是唯一的。只有NaN有多個表示方式。

例如32位浮點數的 NaN 表示為 s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx,當中 s 為符號位,x 不能全為 0。所以共有 2^24-2 個表示方式。

由於有這麼多的NaN,可以利用來表示其他信息,例如作為 variant 表示整數、true、false、null,甚至在64位浮點數中表示指針。這種技術稱為 NaN boxing。


float 和 double 位元組數都不一樣,怎麼可能內存布局一樣?


為什麼知乎客戶端會吞字?

關於內存表示問題樓上已經有人說過了。

猜測應該是問浮點數相等的判定問題吧。

這是兩個問題。

如果a=b則二者一定相等,內存相同(單指有意義的數值,非NaN這種)。但受限於二進位表示的精度,浮點數的相同條件很可能無法滿足。比如經由不同運算得到的兩個數學上相同的數很可能由於計算過程中無法精確表示產生的誤差而不同。所以實際程序中浮點數相等一般是指差值為一個非常小的數,像(a-b小於0.0001)這種做為ab相等的判定。具體看實際需要。

你看下0.3這種數的二進位表示就知道了,很多有理數是無法用浮點數精確表示的,是用的其精度所能達到的最好的近似值來表示的。


相同的浮點數, 這個」相同「是怎麼保證的?

如果是a==b,那可不保證內存dump出來是一樣的。


寫了一個測試程序:(VS2008)

typedef union

{

float fnum;

int inum;

}floatVsIntType;

floatVsIntType a;

floatVsIntType b;

a.fnum = 1.0;

b.fnum = 1.0;

測試結果:

另外:

該實驗只能證明VS2008下直接賦值兩個float的內存狀態是一致的。

在教科書強調浮點數的狀態難以捉摸下(float a = float b ?),我也有提主的疑惑。


現在浮點數通常都按IEEE 754的規矩來,那麼同一個數值,內存表示應當是相同的,除了最高票提到的NaN。

然而,由於不同機器有不同的位元組序,跨硬體平台的數據可能是不同的,需要檢查、轉換位元組序。

當然,首先你得確認真的是「同一個數值」。否則就得按照浮點運算擼棒性的那套方法,容許一些誤差,而不是簡單地用==。


分兩種情況討論:

常量解析依賴編譯器,在同一個編譯器下,同樣表現形式的一個浮點常量應該是一樣的,不同編譯器則可能有差別

計算結果依賴硬體,同樣一段浮點數代碼,就算用同樣的編譯器,在不同機器上都有可能有差別的,因為可能有的用fpu,有的用sse,比較典型的例子是google的一個基於隨機數的浮點計算的一致性hash演算法(記得是叫jumping conhash),在stackoverflow上就被人討論過不同機器的浮點不一致問題,因為這個演算法依賴於所有機器都是同樣計算流程(隨機序列要一致,計算結果也要一致),所以實踐中改成用整數模擬浮點更穩妥


是類似的,只是各組分之間佔用的bit數不同,看這裡:https://en.m.wikipedia.org/wiki/Double-precision_floating-point_format

還有這裡:https://en.m.wikipedia.org/wiki/Single-precision_floating-point_format


兩個一樣的浮點數在同一個CPU同一個操作系統的同一個編譯器下的內存表示是固定的。換句話說,在大部分的應用場合,只要寫在一個程序里,兩個一樣浮點數的內存表示就是一樣的。但是我猜你要問的不是這個。

我們寫上去的浮點數,和實際內存里保存的浮點數,很多情況下是不一樣的。我們知道,表達一個浮點數的內存大小是固定的,所以表達一定是不連續的。因此在保存浮點數的時候,保存的是一個比較接近它的可表達的浮點數(為什麼說比較接近而不是最接近?因為不同的編譯器下,對浮點數的值取捨會不同,所以是最接近的兩個值之一)。換言之,你在寫float a = 1.1的時候,a其實並不是1.1,而是一個和1.1非常接近的,用一定位數的內存在一定的表達規則下可以表示的一個浮點數。擴展之,就是不僅兩個完全一樣的浮點數內存表達一樣,兩個看似不一樣的浮點數的內存表達也可能一樣。比如float a = 1.1和float a = 1.100000000000001。當然這個「看似不一樣」是對我們人類而言的,對於電腦來說,這兩個條件下的a是一樣的,而且都不是1.1。

正因為計算機內的浮點數有這種離散的特性,所以在底層系統進行運算的時候,是不會有浮點數存在的,因為浮點數運算有一定的不確定性。所以教科書里會告訴我們,不要用a == b來比較浮點數。


這個問題是計算機體系結構的問題,跟語言沒關係。不同體系結構的機器,其中的數據表示格式不一定相同。比如,Alpha體系上的浮點是VAX格式,不是IEEE754,當然就不一樣了。

至於大端小端就更不提了。


留個坑回公司答


不才,難以回答。扔你個鏈接:http://en.wikipedia.org


類型決定了一個數1在內存中所佔的位元組數2編譯器如何解釋這些位元組3這個數可以進行哪些操作。

所以兩個不同類型的數,即使在內存中的比特完全一致,它們的值也不一樣,可以進行的操作也可能不一樣。比如int和float,它們對應的比特位可能完全一致,但值可以不同。兩個int用/操作符和兩個float 之間用/操作符意義不同。int可以進行+*-/,結構體不能進行+操作,除非重載運算符。


推薦閱讀:

只使用 C++ 標準語法和標準庫如何做出優美的人機界面?
如何用 C++ 在 10 行內寫出八皇后?
C/C++該採用怎樣的命名規則才能讓自己的代碼足夠清晰呢?
如何才能學到Qt的精髓?
C++20有望實現自動PIMPL嗎?

TAG:C編程語言 | C | 浮點數 |