1. 程式人生 > 其它 >為什麼不同的計算機裡的浮點數會不一樣

為什麼不同的計算機裡的浮點數會不一樣

最近有被問到“你知道為什麼不同計算機裡的浮點數會不一樣嗎”

“不太清楚”

“你沒有好奇去不同的機器上嘗試打印出來嗎”

“沒有...”

很慚愧,發現自己對這些計算機底層原理還不是很熟,並且自己也沒有實際的去嘗試過好奇過,人吶,還是要對知識的追求繼續保持好奇態度的!

先簡單的做個測試,我在mac上計算0.1+0.2,發現出來的值不是0.3,而是0.300000000004. 這不是什麼 bug,也不是 Python 有問題,而是浮點數在做運算時必然的結果!

首先我們先看一下浮點數的二進位制結構是什麼樣的,從下圖可以看到,第一個是符號位,後面5位是指數區域,剩下的10位就是尾數區域

IEEE 754浮點數格式的科學計數法格式: 

N = (-1)s* 1.f * 2

 8.5 的例子可以表示為 23 + 1/2 ,是因為 8 和 0.5 剛好都是 2 的次方數,所以完全不會產生任何精準度問題。但如果是 8.9 的話因為沒辦法換成 2 的次方數相加,所以最後會被迫表示成 1.0001110011… * 23,而且還會產生大概 0.0000003 的誤差。這樣的誤差積少成多,在操作頻繁之後就會累積起來越來越大,導致誤差明顯。比如幀同步中一致性的問題。

  總結 為什麼 0.1 + 0.2 != 0.3 呢?首先,0.1 和 0.2 這兩個實數無法用二進位制精確表示。在二進位制的世界裡,只有包含因子 5 的十進位制數才有可能精確表示,而 0.1 和 0.2 轉換為二進位制後是無限迴圈小數,在計算機中儲存的值只能是真實值的近似表示
,這裡是第一次精度丟失;其次,計算機浮點數採用了 IEEE 754 標準格式,IEEE 754 嚴格規定了尾數域和指數域可表示的大小,位數有限,意味著可表示的資訊量是有限的,換句話說就會存在三種誤差:上溢、下溢和舍入誤差。而 0.1 + 0.2 的結果的尾數域部分剛好超過了尾數域位數,超過位數的部分捨去,存在舍入誤差,這裡是第二次精度丟失
如何減少誤差呢
  • 在某些語言會提供所謂的 epsilon,用來讓你判斷是不是在浮點誤差的允許範圍內,以 Python 來說 epsilon 的值大約是 2.2e-16 
  • 直接用十進位制來計算

Reference:
  1. https://juejin.cn/post/6860445359936798734