首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 金融計算必用 BigDecimal:避免浮點數精度陷阱

     編輯:程式設計綜合問答

直接回答

涉及金錢計算,必須使用 java.math.BigDecimal。 絕不可用 float 或 double。

為何 float/double 不行?

System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(1.03 - 0.42); // 0.6100000000000001

IEEE 754 二進制浮點數無法精確表示許多十進制小數(如 0.1、0.01),導致財務系統出現「分帳不平」、「利息計算偏差」等嚴重錯誤。

BigDecimal 正確用法

1. 建構:請用字串建構子,避免 double 殘留誤差

// 錯誤:new BigDecimal(0.1) → 0.10000000000000000555...
// 正確:
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal sum = a.add(b); // 0.3 精確

2. 四則運算

add(subtract(multiply(divide)
// 除法必須指定精度與捨入模式
BigDecimal c = a.divide(b, 10, RoundingMode.HALF_UP); // 保留10位,四捨五入

3. 比較大小

a.compareTo(b) // 返回 -1/0/1,勿用 equals(會比較 scale)

4. 格式化輸出

NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.TAIWAN);
fmt.setMaximumFractionDigits(2);
System.out.println(fmt.format(amount)); // NT$1,234.56

常見陷阱與避坑指南

陷阱錯誤寫法正確寫法
建構子傳 doublenew BigDecimal(0.1)new BigDecimal("0.1") 或 valueOf(0.1)
除法不指定精度a.divide(b)a.divide(b, scale, RoundingMode.HALF_UP)
用 equals 比較a.equals(b)a.compareTo(b) == 0
直接序列化到 JSONJackson 預設輸出數字配置 JsonSerialize(using = ToStringSerializer.class) 輸出字串,防前端 JS 精度丟失

效能考量

  • BigDecimal 為不可變物件,頻繁運算會產生大量臨時對象。高頻交易系統可考慮:
  • 使用 long 儲存「分」為單位的整數(1 元 = 100 分),運算時用長整數,顯示時除以 100 格式化。
  • 或引入專門庫如 JSR 354 Money API。

結語

金融系統的基石是精確度。BigDecimal 雖稍顯繁瑣,卻是避免資損、合規審計的必要成本。養成「字串建構、除法指定精度、compareTo 比較」三大習慣,即可杜絕 99% 的浮點數 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved