浮點數運算精度問題導致直接截斷或四捨五入易出錯。本文總結三種主流處理方式,並說明適用場景與效能差異。
double value = 123.456789;
BigDecimal bd = BigDecimal.valueOf(value); // 避免 new BigDecimal(double) 精度問題
// 保留 2 位,四捨五入
double result = bd.setScale(2, RoundingMode.HALF_UP).doubleValue();
System.out.println(result); // 123.46
// 連續運算建議全程用 BigDecimal
BigDecimal price = BigDecimal.valueOf(19.99);
BigDecimal qty = BigDecimal.valueOf(3);
BigDecimal total = price.multiply(qty).setScale(2, RoundingMode.HALF_UP);
double val = 123.456;
String formatted = String.format("%.2f", val); // "123.46"
System.out.printf("價格: %.2f 元%n", val); // 直接輸出
// 注意:僅改變字串表示,不改變數值本身
DecimalFormat df = new DecimalFormat("#.00"); // 強制兩位小數
df.setRoundingMode(RoundingMode.HALF_UP);
String s = df.format(123.4); // "123.40"
String s2 = df.format(123.456); // "123.46"
// 進階模式:千分位分隔、百分比
DecimalFormat df2 = new DecimalFormat("#,##0.00");
System.out.println(df2.format(1234567.89)); // "1,234,567.89"
| 方式 | 精度 | 效能 | 適用場景 |
|---|---|---|---|
| BigDecimal | 精確 | 較低 | 金融計算、累加運算、資料庫存儲 |
| String.format | 四捨五入 | 中等 | 日誌輸出、UI 顯示、快速原型 |
| DecimalFormat | 四捨五入 | 中等 | 複雜格式(千分位、百分比、前綴) |
new BigDecimal(0.1) → 實際值為 0.10000000000000000555...,務必用 BigDecimal.valueOf(double) 或 new BigDecimal("0.1")。2.0 - 1.1 可能得到 0.8999999999999999,顯示前必須格式化。String 或 BigDecimal,避免 double 精度丟失。public static double round2(double v) {
return BigDecimal.valueOf(v).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
public static String fmt2(double v) {
return String.format("%.2f", v);
}