數值、單位與位元
為何 0.1+0.2 有時不等於 0.3?
使用工具
合計應為 0.3,畫面卻顯示 0.30000000000000004。保留兩位小數看起來正常,不代表根本問題解決了。近似表示與捨入發生的階段都會影響合計和比較,應先用小運算式理解原因,而不是只隱藏尾數。
高精度計算機處理輸入十進位數的四則運算,浮點內部表示工具則查看 binary32 或 binary64 編碼。相同輸入對應的問題不同,比較是為了選擇適合任務的表示,而不是宣稱哪一種永遠正確。
先直接計算預期運算式
0.1 + 0.2結果為 0.3。再用半形運算子輸入 0.1 + 0.2 - 0.3,得到 0。此計算機將十進位字面值當作分數處理,中間四則運算不轉為一般 Number。但無限小數的顯示仍需指定精度與捨入,「高精度」不代表無限位顯示。
與程式比較時應使用相同輸入字串。如果先經過其他步驟捨入再複製,條件已經不同。分別記錄原始輸入、實際運算式與顯示前捨入,有助於找到最早出現差異的位置。
把 0.1 放進有限二進位位數會怎樣?
在浮點工具選擇十進位輸入與 binary32,輸入 0.1,儲存值顯示為 0.10000000149011612,十六進位為 3dcccccd。有限位數選擇的是接近 0.1 的值,不是完全相同值,這是表示限制而非輸入錯誤。
再輸入 0.5,同一格式儲存值就是 0.5,十六進位為 3f000000。不是所有小數都有這種近似;關鍵是有限十進位不一定對應有限二進位,也不能因此認為所有小數運算誤差相同。
顯示 0.1,不證明內部精確存了 0.1
改為 binary64 後,值欄顯示 0.1,十六進位為 3fb999999999999a。顯示變短不證明內部精確存了十進位 0.1,工具同時提供可讀值與位元表示,就是為了區分這兩個觀點。
比較時會暴露這種差異:顯示都為 0.3 的值,內部未必相等。但到處加同一個小常數也不是通用修復。若採用容差,應依數量尺度與所需精度制定,不應只因浮點行為就改變金額或計數規則。
這裡的精度是有效數字位數
精度設定表示有效數字位數。精度 3、四捨五入時,12345 變為 12300,0.012345 變為 0.0123,不是保留小數點後三位。用於固定小數金額顯示前,應確認此差別。
12345
0.012345
1 / 3
(1 / 3) * 31÷3 顯示 0.333,但 (1÷3)×3 得到 1,因為式內中間分數保留到最終輸出。若複製顯示值 0.333 再乘 3,結果是 0.999。把可見中間位數當作下一次輸入,就改變了計算條件。
恰好一半時,捨入規則會產生不同結果
精度 2 時,1.25 用四捨五入得到 1.3,用捨入至偶數得到 1.2。後者在恰好中間時選擇保留末位為偶數的一側。1.35 兩者都為 1.4,因此單一範例一致不能證明規則相同。
負數時,「捨去」之類說法可能含糊。精度 2 的 -1.29,朝零為 -1.2,朝負無窮為 -1.3。應區分縮小絕對值與數線向左移動。規範若只寫「捨去」,還須確認負數與具體預期值。
逐項捨入,還是合計後捨入?
兩個 1.25 若分別依兩位有效數字四捨五入,得到 1.3+1.3=2.6;先相加再捨入則為 2.5。規則相同但時機不同,結果仍不同。稅額、費用或點數不一致時,也要確認依單品還是訂單合計處理。
正確順序由契約或計算規範決定,不由計算機決定。捨入值無法還原被丟棄尾數,實驗應保留原輸入。減少中間捨入也不總是正確;規則若要求逐項處理,省略後就是另一種計算。
可重現報告要保留運算式與捨入條件
應記錄輸入字串、運算式、數值格式、有效位數、捨入規則與階段。「1.25 在精度 2、捨入至偶數時為 1.2」可重現,「小數不對」則不行。縮短顯示位數不會改變中間型別或傳輸精度。
依序測試簡單加法、無限小數除法、恰好中間值、負數以及合計前後捨入,可將表示問題與業務規則分開。計算機檢查運算式,不判斷量測資料是否準確或是否符合稅費制度。
精確計算不能提高原始量測的準確度
感測器只顯示到十分位時,精確計算可以忠實相加輸入文字,卻不能還原感測器已捨掉的部分。輸出更多位不等於更了解量測對象,十位答案不會創造十位量測精度。工具不自動傳播量測不確定度,因此輸入來源仍需單獨確認。
契約明確規定的 0.10 與感測器近似讀數不同。外觀相同的小數可能是精確約定、量測或其他畫面已捨入的結果。僅避免浮點數不能解決這些語意,應結合輸入來源,分別規定儲存、中間運算和最終顯示的精度規則。