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

Java 浮點數精度損失底層原理與 BigDecimal 完美解決方案

     編輯:Java 相關知識

現象演示


System.out.println(19.99 + 20);    // 39.989999999999995
System.out.println(1.0 - 0.66);    // 0.33999999999999997
System.out.println(0.033 * 100);   // 3.3000000000000003
System.out.println(12.3 / 100);    // 0.12300000000000001

根本原因:IEEE 754 二進制表示

  • 計算機用二進制存儲浮點數(float 32位、double 64位)。
  • 十進制小數往往無法用有限二進制精確表示(如 0.1 = 0.0001100110011... 循環)。
  • double:1位符號 + 11位指數 + 52位尾數。超出精度範圍必然截斷捨入。
  • 類比:十進制中 1/3 = 0.333... 無法精確表示,二進制中 0.99 同理。

錯誤示範


// 錯誤:double 轉 String 再構造 BigDecimal,精度已損失
BigDecimal bd = new BigDecimal(0.1); 
// 正確:直接用字符串構造
BigDecimal bd = new BigDecimal("0.1");

最佳實踐:BigDecimal 工具類


public class DecimalUtil {
    // 加
    public static double add(String a, String b) {
        return new BigDecimal(a).add(new BigDecimal(b)).doubleValue();
    }
    // 減
    public static double sub(String a, String b) {
        return new BigDecimal(a).subtract(new BigDecimal(b)).doubleValue();
    }
    // 乘
    public static double mul(String a, String b) {
        return new BigDecimal(a).multiply(new BigDecimal(b)).doubleValue();
    }
    // 除(指定精度、四捨五入)
    public static double div(String a, String b, int scale) {
        return new BigDecimal(a).divide(new BigDecimal(b), scale, RoundingMode.HALF_UP).doubleValue();
    }
}

// 測試
public static void main(String[] args) {
    String a = "3.14159267", b = "2.358";
    System.out.println("add: " + DecimalUtil.add(a, b));  // 5.49959267
    System.out.println("sub: " + DecimalUtil.sub(a, b));  // 0.78359267
    System.out.println("mul: " + DecimalUtil.mul(a, b));  // 7.40787551586
    System.out.println("div: " + DecimalUtil.div(a, b, 8)); // 1.33231241
}

核心原則

商業計算嚴禁使用 float/double。全鏈路使用 String 存儲數值,計算時轉 BigDecimal,結果再轉 String 或 double(僅用於展示)。

補充:JDK 內部實現

Java 遵循 IEEE 754 標準,採用科學計數法:值 = 符號 × 尾數 × 2^指數。詳細位級存儲與運算邏輯可參考《深入理解 Java 虛擬機器》相關章節。

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