Math.Round 預設使用 銀行家四捨五入 (Banker's Rounding, MidpointRounding.ToEven):.5 時向最鄰近的偶數進位。這符合 IEEE 754 標準,可減少大量資料統計偏差,但常與業務預期的「四捨五入 (AwayFromZero)」不符。本文說明行為差異、正確用法與替代方案。
| 程式碼 | 預設 (ToEven) | AwayFromZero | 業務預期 |
|---|---|---|---|
Math.Round(2.5, 0) | 2 | 3 | 3 |
Math.Round(3.5, 0) | 4 | 4 | 4 |
Math.Round(1.25, 1) | 1.2 | 1.3 | 1.3 |
Math.Round(-2.5, 0) | -2 | -3 | -3 |
// 四捨五入 (遠離零)
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // 3
Math.Round(1.25, 1, MidpointRounding.AwayFromZero); // 1.3
// 銀行家四捨五入 (預設)
Math.Round(2.5, 0, MidpointRounding.ToEven); // 2
Math.Round(2.5); // 2 (隱含 ToEven)
ToEven。| 方法 | 適用型別 | 行為 | 效能 | 備註 |
|---|---|---|---|---|
Math.Round(v, d, AwayFromZero) | double, decimal | 四捨五入 | 高 | 推薦標準做法 |
decimal.Round(v, d, AwayFromZero) | decimal | 四捨五入 | 高 | decimal 專用,精度更好 |
(long)Math.Floor(v + 0.5) | double | 四捨五入 (正數) | 極高 | 負數需特殊處理 |
v.ToString("F2") | double, decimal | 四捨五入格式化 | 中 | 僅供顯示,回傳字串 |
Convert.ToInt32(v) | double, decimal | 銀行家四捨五入 | 高 | 行為同 Math.Round 預設 |
0.1 + 0.2 != 0.3)。x.x5、負數、零、極大值建立測試案例。public static class Rounding
{
/// 四捨五入 (遠離零),適用於金融計算
public static decimal RoundHalfUp(this decimal value, int decimals = 2)
{
return decimal.Round(value, decimals, MidpointRounding.AwayFromZero);
}
/// 四捨五入到整數
public static long RoundHalfUp(this decimal value)
{
return (long)decimal.Round(value, 0, MidpointRounding.AwayFromZero);
}
}
// 使用
decimal price = 12.345m;
price.RoundHalfUp(2); // 12.35
price.RoundHalfUp(); // 12
Math.Round 預設行為符合國際標準,但不符合大多數業務直覺。永遠明確指定 MidpointRounding.AwayFromZero,並搭配 decimal 型別進行貨幣計算,才能避免「少一分、多一分」的經典 Bug。