浮點數為何不能進行相等性比較

2022-07-11 21:18:11 字數 2495 閱讀 2992

最近看扎瓦的時候看到了對浮點數的介紹,並且指明浮點數不能進行相等性運算,這個在接觸c的時候就知道了,

但是一直不知道為什麼。具體的原因不知道也不影響使用,但是不符合我想走的學院派風格,所以大概的看了看。

現在的浮點數在記憶體中的表示方法有ieee規定。也不知道為什麼是電子電氣規定計算機的事。。。

不管是float還是double都是以這種形式儲存的。

sign表示符號位,0正 1負應該不陌生,至於後面的exponent,fraction當時老師也沒有說,現在我就掰一掰吧。

以一般的64位機為例

float佔4個位元組,32位。同理,double8個位元組64位。

sign exponent fraction

float 1 8 23 32

double 1 11 53 64

這樣在記憶體中儲存的形式就很明了了,接下在接解釋為什麼這樣存。

*二進位制浮點數是以符號數值表示法格式儲存,將最高效位元指定為符號位元(sign bit);「指數部份」,

即剩下的f位元,為有效位數(significand)減掉有效位數本身的最高效位元。*

翻譯過來的意思就是:藍色框框sign放符號,綠色框框exponent放處理過的指數部分,粉色框框fraction放處理過的轉化成二進位制的數字。

舉個例子

123.123(10)

二進位制為: 1111011.00011111011111001110110110010001(2)

你是不是曾天真的以為上面的形式是表示它在計算機裡的儲存形式是

0 10010011(.)00011111011111001110110?

完全不是,我曾就天真的以為,真正的是這樣。

0 10000110(.)11101100011111011111001

它經過我上面說過的「處理」,即

significand:

1111011.00011111011111001110110110010001

轉化為科學技術法為

1.11101100011111011111001110110110010001*2^7。

並省略最高為的有效數也就是小數點前的那個「1」,此時因為significand只能儲存23位,

則將超出部分去掉,那麼,significand就變為:

11101100011111011111001

exponent

這一部分為指數域,其值為偏置量bias也就是(2^8)-1:127,加上上面科學計數法的指數值 

127+7=134(10)=10000110(2)。

那麼123.123在記憶體中的儲存形式為:

符號域   指數域         小數域

0     10000110  .  11101100011111011111001

接下來就可以解釋一些關於浮點數的精度問題了。

這是我寫的乙個簡單的扎瓦,c可能隱藏這樣的問題,但是扎瓦輸出就會有問題。反正輸出肯定不是0.6

後面跟了乙個莫名奇妙的1。

0.4(10) = 0.0110011001100110011001100110011....

0.2(10) = 0.00110011001100110011001100110011....

相加後為

0.10011001100110011001100110011001

在記憶體中的儲存形式:

0 1111110 0011001100110011001100110011001

可以想到,因為計算機對於小數部分的限制,它在處理的時候直接把多出來的截掉了。

我用的是double,它會取前53位。那麼0.2和0.4就是損失了精度。結果當然不是0.6。

但是,另寶寶詫異的是,為什麼反而多了。。。

要注意,小數部分裡,除了0.5(10) = 0.1(2)來表示之外,其他的都是近似值。

目前是比較能說服我的,雖然沒有完全弄懂,就當是給以後乙個機會吧。

浮點數進行計算

public static void main string args 為什麼會出現這種情況?計算機採用二進位制進行計算,有些資料可以用二進位制表示。如0.5 1 2 2 1 但是有些不行,如0.1,這就好像1 3用十進位制無法準確的表示。計算機採用機器語言來表示數值,即二進位制 名稱意義 原碼正數...

為什麼浮點數不能精確表示?

我們知道,在編寫程式時,兩個浮點數 float或double 不能直接進行大小比較。當然,我們也都知道,不能直接進行大小比較的原因是因為浮點數在計算機內部不能精確的表示。可是,為什麼在計算機內部浮點數不能夠精確地表示呢?這還得從ieee 754標準說起。根據ieee 754標準,浮點數在計算機內部儲...

為何不能在INPUT鏈上進行SNAT呢

如果你man一下iptables,會發現 snat this target is only valid in the nat table,in the postrouting chain.然而我認為在input上做snat有時還是有必要的。下面說一下原因。snat用於隱藏下行網路,當然,資料已經到達...