double 超過 15 位有效數字即以科學記號顯示,且二進制浮點無法精確表示 0.1 等十進制小數DecimalFormat 只能控制顯示格式,無法解決運算精度問題 (如 1234567890123456.78 會四捨五入)scale (小數位數) 與 RoundingMode 精確控制捨入import java.math.BigDecimal;
public class BigDecimalDemo {
public static void main(String[] args) {
// 必須用字串建構,避免 double 二進制誤差
BigDecimal bd = new BigDecimal("12345678901234578.789");
System.out.println("原值: " + bd);
// 乘法
BigDecimal mul = bd.multiply(new BigDecimal("12.5"));
System.out.println("× 12.5 = " + mul); // 154320986265432234.8625
// 除法:必須指定精度與捨入模式,否則無限循環小數拋 ArithmeticException
BigDecimal div = bd.divide(new BigDecimal("12.5"), 10, BigDecimal.ROUND_HALF_UP);
System.out.println("÷ 12.5 = " + div); // 9876543120987663.0312
// 比較大小 (不可用 equals,會比較 scale)
System.out.println("compareTo: " + bd.compareTo(new BigDecimal("12345678901234578.789"))); // 0
// 格式化輸出
System.out.println("toPlainString: " + bd.toPlainString()); // 無科學記號
}
}
new BigDecimal(double) 禁止使用// 錯誤示範
BigDecimal wrong = new BigDecimal(0.1);
System.out.println(wrong); // 0.1000000000000000055511151231257827021181583404541015625
// 正確示範
BigDecimal right = new BigDecimal("0.1");
// 或
BigDecimal right2 = BigDecimal.valueOf(0.1); // 內部用 Double.toString 產生最短精確字串
原因:double 0.1 在 IEEE 754 中實際為 0.10000000000000000555...,直接建構會保留這個誤差。
divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
// scale: 結果小數位數
// roundingMode: ROUND_HALF_UP (四捨五入)、ROUND_DOWN (捨去)、ROUND_CEILING (向正無窮) 等
| 模式 | 行為 | 範例 (scale=2) |
|---|---|---|
| ROUND_HALF_UP | 四捨五入 | 1.235 → 1.24 |
| ROUND_HALF_DOWN | 五捨六入 | 1.235 → 1.23 |
| ROUND_HALF_EVEN | 銀行家捨入 (預設) | 1.235 → 1.24, 1.225 → 1.22 |
| ROUND_DOWN | 截斷向零 | 1.239 → 1.23 |
| ROUND_UP | 進一法 | 1.231 → 1.24 |
long cents)Apache Commons Math, JScience)DECIMAL/NUMERIC 型別,避免應用層轉換BigDecimal.valueOf(double)compareTo(),不要用 equals()toPlainString() 或資料庫原生 DECIMALMathContext (精度、捨入) 為常數複用