最近有被問到「你知道為什麼不同計算機裡的浮點數會不一樣嗎」
「不太清楚」
「你沒有好奇去不同的機器上嘗試列印出來嗎」
「沒有...」
很慚愧,發現自己對這些計算機底層原理還不是很熟,並且自己也沒有實際的去嘗試過好奇過,人吶,還是要對知識的追求繼續保持好奇態度的!
先簡單的做個測試,我在mac上計算0.1+0.2,發現出來的值不是0.3,而是0.300000000004. 這不是什麼 bug,也不是 python 有問題,而是浮點數在做運算時必然的結果!
首先我們先看一下浮點數的二進位制結構是什麼樣的,從下圖可以看到,第乙個是符號位,後面5位是指數區域,剩下的10位就是尾數區域
ieee 754浮點數格式的科學計數法格式:
n = (-1)s* 1.f * 2e
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 的結果的尾數域部分剛好超過了尾數域位數,超過位數的部分捨去,存在捨入誤差,這裡是第二次精度丟失
如何減少誤差呢
reference:
計算機的浮點數表示
假設有乙個浮點數 float fl 3.14159267 和圓周率很像啊 它在計算中的是怎樣儲存的呢?步驟1 轉換為二進位制表示,浮點數分為整數部分和小數部分,對於該浮點數來說,整數部分為3,浮點數部分為0.14159267.這裡假設fl是4個位元組,32位浮點數表示.十進位制 二進位制 3 000...
計算機中的浮點數
寫這篇blog,是因為在上工程碩士數學時候,又開始講到了浮點數的儲存,運算和精度的問題。這個問題已經見了好多次了,從微機原理的課到計算機視覺處理矩陣時候的conditioning,到這次。但感覺一直都沒有理清楚。所以這次嘗試梳理一下。一般主要分為兩種形式,這裡以8位的儲存進行解釋 所以用浮點數表示數...
計算機浮點數 float 表示
這篇文章講得比較淺顯易懂,所以轉一下。必須對計算機原理的原碼 反碼 補碼 移碼有個清晰的認識,另外參考一下ieee754,否則也會有不明白的地方。括號內為本人看法或觀點。我想浮點數的實現與編譯器也會有很大關係的。前兩天仔細看了看,覺得研究計算機如果不說說如何表示浮點數就太不厚道了.很多人也寫過,這裡...