Java中使用BigDecimal解決價格運算丟失精度

java中關於精度丟失的情況:

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);
輸出的結果爲:

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

----------------------------------------------------------------------------------------------------

而使用BigDecimal的String構造器

BigDecimal b1 = new BigDecimal("0.05");
BigDecimal b2 = new BigDecimal("0.01");
System.out.println(b1.add(b2));
使用String構造器其結果爲:0.06;

在BigDecimal源碼中有說明:如果使用BigDecimal中double構造器,其運算結果會無限接近正確結果:

如:

BigDecimal b1 = new BigDecimal(0.05);
BigDecimal b2 = new BigDecimal(0.01);
System.out.println(b1.add(b2));

使用double構造器其結果爲:0.06000000000000000298372437868010820238851010799407958984375,比結果大,既無限接近正確結果;

源碼中的說明大概爲:如果要使用double這個構造器,就要把參數使用Double的toString的方法(方法裏面放double)轉換爲String,

然後使用BigDecimal(String)去構造,即:我們要用的話:要把double轉爲String,然後還要用BigDecimal的String構造器.


在價格運算應用中一定要用BigDecimal的String構造器;

封裝成一個BigDecimalUtil:

public class BigDecimalUtil {

    private BigDecimalUtil() {}
    // +
    public static BigDecimal add(double v1, double v2) {
        //轉換爲String,然後就會調用String構造器
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }

    // -
    public static BigDecimal sub(double v1, double v2) {
        //轉換爲String,然後就會調用String構造器
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2);
    }

    // *
    public static BigDecimal mul(double v1, double v2) {
        //轉換爲String,然後就會調用String構造器
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2);
    }

    // /
    public static BigDecimal div(double v1, double v2) {
        //轉換爲String,然後就會調用String構造器
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        //要考慮除不盡的情況(更多需求需瞭解divide源碼
        return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);//四捨五入,保留兩位小數
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章