float/double 基於 IEEE 754 浮點數表示,無法精確表達許多十進制小數(如 0.1),導致財務、科學計算出現誤差:
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(1.0 - 0.9); // 0.09999999999999998
BigDecimal 提供任意精度的有理數運算,是金融、計量等精度敏感領域的標準選擇。
import java.math.BigDecimal;
import java.util.Scanner;
public class BigDecimalAddition {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("請輸入第一個大數: ");
String num1 = scanner.next();
System.out.print("請輸入第二個大數: ");
String num2 = scanner.next();
// 推薦使用 String 構造器,避免 double 精度損失
BigDecimal bd1 = new BigDecimal(num1);
BigDecimal bd2 = new BigDecimal(num2);
BigDecimal sum = bd1.add(bd2);
System.out.println("精確相加結果: " + sum);
scanner.close();
}
}
| 操作 | 方法 | 說明 |
|---|---|---|
| 加法 | add(BigDecimal) | 返回新 BigDecimal,原對象不可變 |
| 減法 | subtract(BigDecimal) | |
| 乘法 | multiply(BigDecimal) | |
| 除法 | divide(BigDecimal, scale, RoundingMode) | 必須指定精度與舍入模式,否則可能拋 ArithmeticException |
| 比較 | compareTo(BigDecimal) | 返回 -1/0/1,勿用 equals(比較 scale) |
| 格式化 | setScale(scale, RoundingMode) | 設置小數位數與舍入規則 |
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// 保留 2 位小數,四捨五入
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
// 結果: 3.33
// 不指定精度會拋異常:Non-terminating decimal expansion
// BigDecimal wrong = a.divide(b); // ❌
// ❌ 錯誤:double 精度損失已在構造前發生
new BigDecimal(0.1); // 0.1000000000000000055511151231257827021181583404541015625
// ✅ 正確:String 構造器精確表達
new BigDecimal("0.1"); // 0.1
// ✅ 正確:valueOf 內部用 Double.toString 轉換
BigDecimal.valueOf(0.1); // 0.1
long 整數分/厘存儲MathContext 統一精度與舍入模式@Column(precision=19, scale=4) 對應 BigDecimalJsonSerialize(using = ToStringSerializer.class) 避免科學計數法