為什么不同的計算機里的浮點數會不一樣


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

“不太清楚”

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

“沒有...”

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

先簡單的做個測試,我在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM