2020年9月20日 星期日

[筆記] Round() 不一定是四捨五入

  使用程式語言函式庫提供的 `Round()` 之類的函式對數值做四捨五入時,要小心它的捨入結果可能不是所預期的四捨五入,因而踩到雷。
來看看 Python 的:

來看看 JavaScript 的:

最後看看 C# 的:

可以發現,對 1.5 跟 3.5 都是四捨五入到 2 與 4,可是在 Python 與 C# 中,對 2.5 的結果卻是 2。

  這是因為 Python 與 C# 的 `Round()` 使用的是稱為「銀行家捨入」(bankers' rounding)的捨入方式,也就是對於捨入中間點(以捨入到整數來說,0.5 就是中間點,因為它距離 1 和 2 是相等的)會選擇以靠近偶數的方向捨入(To even)。而常見的四捨五入則是將捨入中間點往遠離 0 的方向捨入(Away from 0,所以 -2.5 做四捨五入後是 -3),然而這種捨入方式會讓結果與原本值誤差越來越大。

如圖所示,在銀行家捨入中,會讓捨入中間點以一入一捨的方式進位,藉此減少因捨入而造成的誤差。舉例來說:有三筆資料 1.5、2.5、3.5,其總和為 7.5,如果在儲存時是以四捨五入法存入,則為 2、3、4,其總和為 9,但是如果是以銀行家捨入存入,則為 2、2、4,其總和為 8,後者的誤差較小。

參考資料


沒有留言:

張貼留言