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

BigDecimal 精度原理:十進制縮放而非二進制浮點

     編輯:程式設計綜合問答

BigDecimal 能保證小數精確計算,核心原理是**十進制縮放整數運算**,而非二進制浮點近似。本文從內部結構、運算邏輯、與 float/double 對比三個維度解析。

核心結構


// 簡化版 BigDecimal 內部結構
public class BigDecimal {
    private final BigInteger intVal; // 無標度值:整數
    private final int scale;         // 標度:小數點右移位數
    // 實際值 = intVal / 10^scale
}

原理解析

1. 十進制縮放

  • 輸入 "123.456" → intVal = 123456, scale = 3
  • 實際值 = 123456 / 10^3 = 123.456
  • 所有運算轉為 **BigInteger 整數運算** + **標度對齊**

2. 加法示例


// 1.23 + 4.5
// intVal: 123 (scale=2), 45 (scale=1)
// 對齊標度:45 → 450 (scale=2)
// 整數相加:123 + 450 = 573
// 結果:intVal=573, scale=2 → 5.73

3. 乘法示例


// 1.2 × 3.45
// intVal: 12 (scale=1), 345 (scale=2)
// 整數相乘:12 × 345 = 4140
// 標度相加:1 + 2 = 3
// 結果:intVal=4140, scale=3 → 4.140

4. 除法:需指定精度與舍入模式


// 1 ÷ 3 無限循環小數
BigDecimal result = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 
    10, RoundingMode.HALF_UP); // 保留10位,四捨五入
// 0.3333333333

對比:float/double 為什麼不精確

特性float/double (IEEE 754)BigDecimal
表示方式二進制科學計數法:±1.xxx × 2^exp十進制縮放:intVal × 10^(-scale)
0.1 表示無限循環二進制:0.0001100110011... → 截斷誤差精確:intVal=1, scale=1
運算誤差累積放大無誤差(整數運算)
性能硬件加速、極快軟件實現、較慢
適用場景科學計算、圖形、非金融金融、貨幣、精確計價

BigInteger 同樣是二進制,為何不影響?

BigInteger 存儲**十進制數值對應的整數**,而非二進制浮點近似值。例如十進制 123456 在內存中是二進制 11110001001000000,但這代表**確切的整數 123456**,不存在精度損失。BigDecimal 只是在其基礎上記錄「小數點位置」。

使用陷阱與最佳實踐

陷阱 1:double 構造器引入誤差


// 錯誤
new BigDecimal(0.1); // 實際值 0.10000000000000000555...
// 正確
new BigDecimal("0.1"); // 字符串構造,精確
BigDecimal.valueOf(0.1); // 靜態工廠,內部用 Double.toString

陷阱 2:equals 比較包含標度


new BigDecimal("1.0").equals(new BigDecimal("1.00")); // false (scale 不同)
// 比較數值大小用
a.compareTo(b) == 0; // true

陷阱 3:除法不指定精度拋異常


BigDecimal.ONE.divide(BigDecimal.valueOf(3)); // ArithmeticException
// 必須
divide(divisor, scale, RoundingMode.HALF_UP)

總結

BigDecimal 精度來源:**十進制縮放整數運算**。將小數轉為「無標度整數 + 標度」,所有運算歸約為 BigInteger 整數運算,避開二進制浮點無法精確表示十進制小數的根本缺陷。代價是性能下降,但金融領域**精確性優先於性能**。

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