今天在某.NET Core 羣中看到有人在問Math.Round
的問題。其實這個問題之前有很多人遇到了,在此總結一下。
開發者爲了實現小數點後 2 位的四捨五入,編寫了如下代碼,
var num = Math.Round(12.125, 2);
代碼非常的簡單,開發者實際得到的結果是12.12, 這與其所預期的四捨五入結果12.13相悖。
其實產生這個結果的原因是由於Math.Round
默認使用的並非是四捨五入的原則,而是四捨六入五成雙的原則。
四捨六入五成雙
所謂的四捨六入五成雙,就是說當確定有效位數之後,有效位數的下一位如果小於等於4就捨去,如果大於等於6就進一,當有效位數的下一位是5的時候
- 如果5前爲奇數,就舍五進一
- 如果5前爲偶數,就舍五不進(0是偶數)
從統計學上將,四捨六入五成雙比四捨五入要更精確,因爲大量計算的情況下,四捨五入逢五進一,會導致結果偏向大數。
例如:
1.15+1.25+1.35+1.45 = 5.2
如果有效位數是小數點後一位,使用四捨五入原則得到的結果
1.2 + 1.3 + 1.4 + 1.5 = 5.4
而使用四捨六入五成雙原則得到的結果是
1.2 + 1.2 + 1.4 + 1.4 = 5.2
由此可見四捨六入五成雙原則得到的結果更爲精確。
Math.Round的四捨五入
那麼如何使用Math.Round
實現預期的四捨五入呢?
其實C#中的Math.Round
提供了非常多的重載方法,其中有兩個重載方法是,
public static double Round (double value, int digits, MidpointRounding mode);
public static decimal Round (decimal d, int decimals, MidpointRounding mode);
這兩個方法都提供了第三個參數mode
, mode
是一個MidpointRounding
的枚舉變量,它有2個可選值
- AwayFromZero - 四捨五入
- ToEven - 四捨六入五成雙
所以如果我們希望的到一個理想中四捨五入的結果,,我們可以改用如下代碼:
var num = Math.Round(12.125, 2, MidpointRounding.AwayFromZero);