要搞清楚float累加為什麼會產生誤差,必須先大致理解float在機器裡怎麼存儲的, 這裡只介紹一下組成
由上圖可知(摘在[2]), 浮點數由: 符號位 + 指數位 + 尾數部分, 三部分組成。由於機器中都是由二進制存儲的,那麼一個10進制的小數如何表示成二進制。例如: 8.25轉成二進制為1000.01, 這是因為 1000.01 = 1*2^3 + 0*2^2 + 0*2^1 + 0*2^0 + 0*2^-1 + 2*2^-2 = 1000.01.
(2)float的有效位數是6-7位,這是為什麼呢?因為位數部分只有23位,所以最小的精度為1*2^-23 在10^-6和10^-7之間,接近10^-7, 中也有解釋
那麼為什麼float累加會產生誤差呢,主要原因在於兩個浮點數累加的過程。
兩浮點數X,Y進行加減運算時,必須按以下幾步執行:
(1)對階,使兩數的小數點位置對齊,小的階碼向大的階碼看齊。
(2)尾數求和,將對階後的兩尾數按定點加減運算規則求和(差)。
(3)規格化,為增加有效數字的位數,提高運算精度,必須將求和(差)後的尾數規格化。
(4)捨入,為提高精度,要考慮尾數右移時丟失的數值位。
(5)判斷結果,即判斷結果是否溢出。
關鍵就在與對階這一步驟,由於float的有效位數只有7位有效數字,如果一個大數和一個小數相加時,會產生很大的誤差,因為尾數得截掉好多位。例如:
123 + 0.00023456 = 1.23*10^2 + 0.000002 * 10^2 = 123.0002
那麼此時就會產生0.00003456的誤差,如果累加多次,則誤差就會進一步加大。
那麼怎麼解決這種誤差呢?
(1)Kahan summation算法。
(2)使用double類型進行計算,由於double類型的有效數字有15~16位,一般情況下產生誤差可以接受。