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

Java 大數值精確計算:BigDecimal 完整使用指南與避坑

     編輯:Java 相關知識

問題背景

  • double 超過 15 位有效數字即以科學記號顯示,且二進制浮點無法精確表示 0.1 等十進制小數
  • DecimalFormat 只能控制顯示格式,無法解決運算精度問題 (如 1234567890123456.78 會四捨五入)

BigDecimal 核心特性

  • 任意精度有理數 (非標準浮點),整數部分無上限,小數位可任意指定
  • 不可變物件,所有運算方法回傳新實例
  • 提供 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 (向正無窮) 等

常用 RoundingMode 速查

模式行為範例 (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

效能考量與替代方案

  • BigDecimal 物件創建與運算較慢,高頻低延遲路徑可考慮:
    • 定點整數 (以分為單位存儲金額 long cents)
    • 第三方高效能庫 (如 Apache Commons Math, JScience)
    • 資料庫層面直接使用 DECIMAL/NUMERIC 型別,避免應用層轉換

    最佳實務清單

    1. 金額、利率、匯率等財務數值 全程使用 BigDecimal
    2. 建構 只用字串或 BigDecimal.valueOf(double)
    3. 除法 必須指定 scale 與 RoundingMode
    4. 比較用 compareTo(),不要用 equals()
    5. 序列化/持久化時儲存 toPlainString() 或資料庫原生 DECIMAL
    6. 定義常用運算的 MathContext (精度、捨入) 為常數複用
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved