1. 程式人生 > >解決double的精度問題-BigDecimal

解決double的精度問題-BigDecimal

BigDecimal的用法

這裡寫圖片描述
不可變的,任意精度的,有符號十進位制數。

BigDecimal valueOf(double val)

說明文件:

        public static BigDecimal valueOf(double val) {
        // Reminder: a zero double returns '0.0', so we cannot fastpath
        // to use the constant ZERO.  This might be important enough to
        // justify a factory approach, a cache, or a few private
// constants, later. return new BigDecimal(Double.toString(val)); }

所以,
BigDecimal b2 = new BigDecimal(Double.toString(2.283));
BigDecimal b3 = BigDecimal.valueOf(2.283);
兩種double轉BigDecimal的方法其實是等價的,而且第二更簡潔,建議使用第二種。

這裡寫圖片描述

關於型別轉換:
BigDecimal類提供了諸如intValue(),floatValue(), doubleValue(), longValue()方法來將BigDecimal物件轉換成對應的值。如果要使用構造器的話也建議使用String來初始化,因為使用其他型別的初始化的結果是不可預知的。比如BigDecimal(0.1)其實表示的值是和0.1很接近的一個浮點數,但是使用BigDecimal(“0.1”)就是真的0.1。

setScale函式

  • setScale(1)表示保留以為小數,預設用四捨五入方式
  • setScale(1,BigDecimal.ROUND_DOWN)直接刪除多餘的小數位,如2.35會變成2.3
  • setScale(1,BigDecimal.ROUND_UP)進位處理,2.35變成2.4
  • setScale(1,BigDecimal.ROUND_HALF_UP)四捨五入,2.35變成2.4
  • setScaler(1,BigDecimal.ROUND_HALF_DOWN)五舍六入,2.35變成2.3,2.36變成2.40;如果是5則向下舍。

加法

 public static
double sum(double d1,double d2){ BigDecimal bd1 = BigDecimal.valueOf(d1); BigDecimal bd2 = BigDecimal.valueOf(d2); return bd1.add(bd2).doubleValue(); }

減法

 public double sub(double d1,double d2){ 
        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2);
        return bd1.subtract(bd2).doubleValue(); 
    } 

乘法

 public double mul(double d1,double d2){ 
        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2); 
        return bd1.multiply(bd2).doubleValue(); 
    } 

除法

除法要注意,因為BigDecimal 計算時由於除法運算,得到迴圈結果,造成異常!

BigDecimal total = new BigDecimal(200).setScale(3,BigDecimal.ROUND_HALF_UP);

表示這個total的初始值為200.000

BigDecimal total2 = new BigDecimal(10).setScale(3, BigDecimal.ROUND_HALF_UP);

表示這個total2的初始值為10.000

當這個2數相除的時候不能簡單的用total.divide(total2); 如果這樣會報錯:

Non-terminating decimal expansion; no exact representable decimal result

正確的方法:

total.divide(total2,3,BigDecimal.ROUND_HALF_UP);

這樣才不會報錯,你必須為它指定保留小數位,所以除法的常用模式為:

/** 
     * double 除法 
     * @param d1 
     * @param d2 
     * @param scale 四捨五入 小數點位數 
     * @return 
     */ 
    public double div(double d1,double d2,int scale){ 
        //  當然在此之前,你要判斷分母是否為0,   
        //  為0你可以根據實際需求做相應的處理 

        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2); 
        return bd1.divide 
               (bd2,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
    } 

加減乘除運算後的標度問題

除了邏輯的準確結果外,每種算術運算都有一個表示結果的首選標度。下表列出了每個運算的首選標度。
運算 結果的首選標度

  • Add:max(addend.scale(), augend.scale())
  • Subtract:max(minuend.scale(), subtrahend.scale())
  • Multiply:multiplier.scale() + multiplicand.scale()
  • Divide:dividend.scale() - divisor.scale()

這裡寫圖片描述