最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用BigDecimal確保數(shù)值計(jì)算精度的最佳實(shí)踐指南

 更新時(shí)間:2026年01月19日 08:37:38   作者:lagrahhn  
這篇文章主要為大家詳細(xì)介紹了Java使用BigDecimal確保數(shù)值計(jì)算精度的相關(guān)知識,BigDecimal一般適用于金融計(jì)算、高精度運(yùn)算等對數(shù)值準(zhǔn)確性要求高的場景,下面小編就和大家詳細(xì)介紹一下吧

一、常見問題點(diǎn)

使用BigDecimal(double)構(gòu)造函數(shù) 

// 錯(cuò)誤示范
BigDecimal bd = new BigDecimal(0.1); 
System.out.println(bd); // 輸出: 0.1000000000000000055511151231257827021181583404541015625

推薦做法

BigDecimal bd1 = new BigDecimal("0.1");          // 安全
BigDecimal bd2 = BigDecimal.valueOf(0.1);        // 內(nèi)部轉(zhuǎn)字符串,也安全

除法未指定舍入模式導(dǎo)致異常 

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
a.divide(b); // Non-terminating decimal expansion; no exact representable decimal result.

推薦做法

BigDecimal result = a.divide(b, 4, RoundingMode.HALF_UP);
// 或
BigDecimal result2 = a.divide(b, new MathContext(10, RoundingMode.HALF_UP));

建議:所有除法操作都顯式指定精度和舍入方式。

equals()比較包含 scale(小數(shù)位數(shù))

new BigDecimal("1.0").equals(new BigDecimal("1")); // false

正確比較數(shù)值是否相等

new BigDecimal("1.0").compareTo(new BigDecimal("1")) == 0; // true

規(guī)則總結(jié)

  • 數(shù)值相等 → compareTo() == 0
  • 完全相同(含 scale)→ equals()

hashCode()與equals()不一致(因 scale 不同)

Set<BigDecimal> set = new HashSet<>();
set.add(new BigDecimal("1.0"));
set.add(new BigDecimal("1")); // 被視為兩個(gè)不同元素!
System.out.println(set.size()); // 輸出: 2

解決方案:統(tǒng)一格式后再放入集合

BigDecimal normalized = bd.stripTrailingZeros();
set.add(normalized);

stripTrailingZeros()可能返回科學(xué)計(jì)數(shù)法 

BigDecimal bd = new BigDecimal("100");
System.out.println(bd.stripTrailingZeros().toString()); // 輸出: 1E+2

輸出標(biāo)準(zhǔn)十進(jìn)制格式

System.out.println(bd.stripTrailingZeros().toPlainString()); // 輸出: 100

性能問題:頻繁創(chuàng)建對象

  • BigDecimal 是不可變類,每次運(yùn)算都生成新對象。
  • 高頻循環(huán)中可能造成 GC 壓力。

優(yōu)化建議

  • 緩存常用常量:BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN
  • 避免不必要的中間變量

setScale()不改變原對象 

BigDecimal bd = new BigDecimal("1.234");
bd.setScale(2, RoundingMode.HALF_UP); // 無效!
System.out.println(bd); // 仍是 1.234

必須重新賦值

bd = bd.setScale(2, RoundingMode.HALF_UP);

默認(rèn)舍入模式選擇需謹(jǐn)慎

舍入模式說明
HALF_UP四舍五入(最常用)
HALF_EVEN銀行家舍入(減少累積誤差,適合金融)

根據(jù)業(yè)務(wù)需求選擇,不要盲目使用默認(rèn)。

二、toString()vstoPlainString()對比

方法行為適用場景
toString()可能使用科學(xué)計(jì)數(shù)法(如 1.23E-7)日志、調(diào)試
toPlainString()始終返回普通十進(jìn)制格式顯示、存儲、序列化

示例對比:

BigDecimal small = new BigDecimal("0.000000123");
System.out.println(small.toString());        // 1.23E-7
System.out.println(small.toPlainString());   // 0.000000123

BigDecimal trailing = new BigDecimal("100.00");
System.out.println(trailing.toString());        // 100.00
System.out.println(trailing.toPlainString());   // 100.00

BigDecimal large = new BigDecimal("1E+10");
System.out.println(large.toString());        // 1E+10
System.out.println(large.toPlainString());   // 10000000000

建議:對外輸出(如 JSON、UI、數(shù)據(jù)庫)一律使用 toPlainString()。

三、完整測試代碼(驗(yàn)證所有問題點(diǎn))

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.HashSet;
import java.util.Set;

public class BigDecimalPitfallsTest {

    public static void main(String[] args) {
        System.out.println("=== 1. 構(gòu)造函數(shù)陷阱 ===");
        testConstructor();

        System.out.println("\n=== 2. 除法異常 ===");
        testDivision();

        System.out.println("\n=== 3. equals vs compareTo ===");
        testEqualsVsCompareTo();

        System.out.println("\n=== 4. Set 中重復(fù)問題 ===");
        testSetBehavior();

        System.out.println("\n=== 5. stripTrailingZeros 與 toPlainString ===");
        testStripAndToString();

        System.out.println("\n=== 6. setScale 必須重新賦值 ===");
        testSetScale();

        System.out.println("\n=== 7. toString vs toPlainString ===");
        testToStringFormats();
    }

    private static void testConstructor() {
        BigDecimal bad = new BigDecimal(0.1);
        BigDecimal good1 = new BigDecimal("0.1");
        BigDecimal good2 = BigDecimal.valueOf(0.1);
        System.out.println("new BigDecimal(0.1): " + bad);
        System.out.println("new BigDecimal(\"0.1\"): " + good1);
        System.out.println("BigDecimal.valueOf(0.1): " + good2);
    }

    private static void testDivision() {
        BigDecimal a = new BigDecimal("1");
        BigDecimal b = new BigDecimal("3");
        try {
            a.divide(b);
        } catch (ArithmeticException e) {
            System.out.println("除法異常: " + e.getMessage());
        }
        BigDecimal safe = a.divide(b, 6, RoundingMode.HALF_UP);
        System.out.println("安全除法結(jié)果: " + safe);
    }

    private static void testEqualsVsCompareTo() {
        BigDecimal x = new BigDecimal("1.0");
        BigDecimal y = new BigDecimal("1");
        System.out.println("x.equals(y): " + x.equals(y)); // false
        System.out.println("x.compareTo(y) == 0: " + (x.compareTo(y) == 0)); // true
    }

    private static void testSetBehavior() {
        Set<BigDecimal> set = new HashSet<>();
        set.add(new BigDecimal("1.0"));
        set.add(new BigDecimal("1"));
        System.out.println("Set 大?。ㄎ礃?biāo)準(zhǔn)化): " + set.size()); // 2

        Set<BigDecimal> normalizedSet = new HashSet<>();
        normalizedSet.add(new BigDecimal("1.0").stripTrailingZeros());
        normalizedSet.add(new BigDecimal("1").stripTrailingZeros());
        System.out.println("Set 大?。?biāo)準(zhǔn)化后): " + normalizedSet.size()); // 1
    }

    private static void testStripAndToString() {
        BigDecimal bd = new BigDecimal("100");
        System.out.println("stripTrailingZeros().toString(): " + bd.stripTrailingZeros().toString());
        System.out.println("stripTrailingZeros().toPlainString(): " + bd.stripTrailingZeros().toPlainString());
    }

    private static void testSetScale() {
        BigDecimal bd = new BigDecimal("1.234");
        bd.setScale(2, RoundingMode.HALF_UP); // 無效果
        System.out.println("未重新賦值: " + bd); // 1.234

        bd = bd.setScale(2, RoundingMode.HALF_UP);
        System.out.println("重新賦值后: " + bd); // 1.23
    }

    private static void testToStringFormats() {
        BigDecimal[] cases = {
            new BigDecimal("0.000000123"),
            new BigDecimal("100.00"),
            new BigDecimal("12345678901234567890")
        };
        for (BigDecimal bd : cases) {
            System.out.println("原始: " + bd);
            System.out.println("  toString():        " + bd.toString());
            System.out.println("  toPlainString():  " + bd.toPlainString());
            System.out.println();
        }
    }
}

四、最佳實(shí)踐總結(jié)表

場景推薦做法
構(gòu)造優(yōu)先使用 new BigDecimal("xxx") 或 BigDecimal.valueOf(xxx)
比較數(shù)值使用 compareTo() == 0
判斷完全相等使用 equals()(含 scale)
除法運(yùn)算總是指定精度和 RoundingMode
集合存儲先調(diào)用 .stripTrailingZeros() 統(tǒng)一格式
字符串輸出使用 .toPlainString() 避免科學(xué)計(jì)數(shù)法
修改值記住 BigDecimal 不可變,必須重新賦值
舍入策略根據(jù)業(yè)務(wù)選 HALF_UP(通用)或 HALF_EVEN(金融)
性能優(yōu)化緩存常量,避免高頻創(chuàng)建

以上就是Java使用BigDecimal確保數(shù)值計(jì)算精度的最佳實(shí)踐指南的詳細(xì)內(nèi)容,更多關(guān)于Java BigDecimal數(shù)值精度計(jì)算的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

玉门市| 寿宁县| 平潭县| 资溪县| 泸州市| 吉木萨尔县| 松滋市| 普兰县| 连南| 广灵县| 临海市| 长垣县| 巨野县| 黔西| 两当县| 怀集县| 扶沟县| 青川县| 福泉市| 腾冲县| 阜新市| 乡宁县| 株洲市| 高尔夫| 修武县| 安乡县| 墨玉县| 济南市| 兴文县| 清徐县| 东源县| 固始县| 北碚区| 鸡泽县| 兴城市| 奎屯市| 赞皇县| 瑞昌市| 安徽省| 宜阳县| 黄大仙区|