首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 浮點數精度陷阱與 BigDecimal 精確計算實戰

     編輯:Java 相關知識

問題現場:浮點數運算的「驚喜」

System.out.println(0.05 + 0.01); // 0.060000000000000005
System.out.println(1.0 - 0.42);  // 0.5800000000000001
System.out.println(4.015 * 100); // 401.49999999999994
System.out.println(123.3 / 100); // 1.2329999999999999

float/double 採用 IEEE 754 二進制浮點數,無法精確表示許多十進制小數,導致財務、計量場景出現誤差。

DecimalFormat 不靠譜

DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(3.125)); // 3.12 (銀行家捨入:5 向偶數靠攏)
System.out.println(df.format(3.135)); // 3.14

預設 RoundingMode.HALF_EVEN 非商業慣用「四捨五入」,不可靠。

BigDecimal:精確計算的正解

構造器選擇至關重要

BigDecimal bd1 = new BigDecimal(0.05);
System.out.println(bd1); // 0.05000000000000000277555756156289135105907917022705078125

BigDecimal bd2 = new BigDecimal("0.05");
System.out.println(bd2); // 0.05 ✅

// 推薦:valueOf 內部調用 Double.toString
BigDecimal bd3 = BigDecimal.valueOf(0.05); // 等同於 new BigDecimal("0.05")

結論:只能用 String 或 valueOf(double) 構造,絕不可直接用 double 值。

不可變性與運算規則

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("5");

// ❌ 錯誤:a 不會變
a.add(b); 

// ✅ 正確:必須接收返回值
BigDecimal c = a.add(b);       // 加
BigDecimal d = a.subtract(b);  // 減
BigDecimal e = a.multiply(b);  // 乘
BigDecimal f = a.divide(b, 2, RoundingMode.HALF_UP); // 除(需指定精度與捨入模式)

BigDecimal 為不可變對象,每次運算產生新實例,類似 String。

最佳實踐封裝建議

public final class MoneyUtil {
    private static final int SCALE = 2;
    private static final RoundingMode MODE = RoundingMode.HALF_UP;

    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        return a.add(b).setScale(SCALE, MODE);
    }
    // ... subtract, multiply, divide 同理
}

總結

  • 浮點數僅適合科學計算,嚴禁用於金融業務。
  • BigDecimal 必須用 String 或 valueOf 構造。
  • 記住不可變特性,鏈式調用時保留返回值。
  • 除法運算強制指定 scale 與 RoundingMode 避免 ArithmeticException。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved