解決double的精度問題-BigDecimal
阿新 • • 發佈:2019-02-16
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()