四捨五入看似簡單,但 Math.round(-12.5) 回傳 -12 而非 -13 往往讓開發者措手不及。本文詳細解析 Java 圓整機制、銀行家捨入法(Banker's Rounding)原理、七種 RoundingMode 差異,並提供四種保留小數位實作方案。
System.out.println(Math.round(12.5)); // 13
System.out.println(Math.round(-12.5)); // -12 (非 -13)
原因:Math.round 採用 ROUND_HALF_UP 但負數向零方向,實際等同 ROUND_HALF_EVEN 在正數表現,負數卻是 ROUND_HALF_DOWN。
為解決傳統四捨五入在大量資料統計時的偏差(銀行獲利受損),規則如下:
| 原值 | 結果 | 說明 |
|---|---|---|
| 11.556 | 11.56 | 六入 |
| 11.554 | 11.55 | 四捨 |
| 11.5551 | 11.56 | 五後有數進位 |
| 11.545 | 11.54 | 五後無數,前位 4(偶)捨去 |
| 11.555 | 11.56 | 五後無數,前位 5(奇)進位 |
| 模式 | 行為 | 備註 |
|---|---|---|
| ROUND_UP | 遠離零方向 | 只要捨棄位非 0 就進位 |
| ROUND_DOWN | 趨向零方向 | 直接截斷 |
| ROUND_CEILING | 向正無窮 | 正數同 UP,負數同 DOWN;Math.round 行為 |
| ROUND_FLOOR | 向負無窮 | 正數同 DOWN,負數同 UP |
| HALF_UP | 四捨五入(5 進) | 最常用傳統模式 |
| HALF_DOWN | 五捨六入 | 5 當作捨去 |
| HALF_EVEN | 銀行家算法 | IEEE 754 預設、金融推薦 |
double f = 111231.5585;
BigDecimal b = new BigDecimal(String.valueOf(f)); // 避免 double 精度誤差
double f1 = b.setScale(2, RoundingMode.HALF_UP).doubleValue(); // 111231.56
java.text.DecimalFormat df = new java.text.DecimalFormat("#.00");
String s = df.format(3.1415926); // "3.14"
String result = String.format("%.2f", 3.1415926); // "3.14"
System.out.printf("%.2f%n", 3.1415926);
<bean:write name="entity" property="price" format="0.00" />
<fmt:formatNumber type="number" value="${10000.22/100}" maxFractionDigits="2" />
BigDecimal + RoundingMode.HALF_EVEN,並以 String 建構子避免二進位浮點誤差。String.format 或 DecimalFormat 足夠。Math.round 處理負數或精確貨幣計算。