浮點數捨入與為何 0.1 並不精確
在幾乎任何程式語言裡輸入 0.1 + 0.2 並要求結果,你常會得到的不是 0.3,而是 0.30000000000000004。這不是語言的錯誤,也不是你電腦的瑕疵——它是用固定位元數以二進位儲存十進位分數的不可避免後果。理解原因,能把一個令人困惑的意外,變成一個可預期、可管理的人生事實。
核心在於:浮點數以「二進位」儲存數字,而正如 1/3 無法在十進位裡精確寫出(0.3333……永無止境),值 0.1 也無法在二進位裡精確寫出。在二進位下,0.1 是不會結束的循環小數 0.0001100110011……。由於只有固定數量的尾數位元可用,電腦儲存「最接近的可表示值」,它與真正的 0.1 差了一絲。對這些略有偏差的值做算術,那些微小的誤差可能累積或現形,這正是 0.1 + 0.2 落在離 0.3 幾千兆分之一處的原因。每當一個結果無法精確表示,IEEE-754 就把它「捨入」到一個可表示的鄰居,預設捨到最近的那個(平手時捨向最後一位為偶數的值,稱為四捨六入五成雙)。
實務上的教訓很具體。絕不要對浮點數做精確相等比較;在一個適合你問題的小容差內比較。要知道捨入誤差會在長計算中累積,所以運算的「順序」會稍微改變結果。而對於真正必須精確的值——尤其是金錢——根本別用二進位浮點數;改用整數的分、定點表示法,或十進位型別。浮點數是量測和連續量的正確工具,正確到十五位數綽綽有餘;當「差一分錢」不可接受時,它就是錯誤的工具。
在二進位下,0.1 是 0.0001100110011……永遠循環,所以是捨入後儲存。這就是為什麼 0.1 + 0.2 得到 0.30000000000000004,也是為什麼金錢應該用整數的分,而非 double。
0.1 在二進位下不終止,所以以最接近的值儲存。
誤差出在二進位「表示法」上,而非加法:0.1 和 0.2 在你寫下的當下就已略有偏差,所以連單獨儲存 0.1 都不精確。金錢或計數要精確,就得用整數或十進位型別。