咱們知道浮點數是沒法在計算機中準確表示的,例如0.1在計算機中只是表示成了一個近似值,所以,浮點數的運算結果具備不可預知性。java
在進行數字運算時,若是有double或float類型的浮點數參與計算,偶爾會出現計算不許確的狀況。如如下示例代碼:算法
- package ex;
-
- public class BigDeciTest {
- public static void main(String[] args){
- 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
在大多數狀況下,使用double和float計算的結果是準確的,可是在一些精度要求很高的系統中,這種問題是很是嚴重的。
在《Effective Java》中提到一個原則,那就是float和double只能用來做科學計算或者是工程計算,但在商業計算中咱們要用java.math.BigDecimal,經過使用BigDecimal類咱們能夠解決上述問題,實例代碼以下:ide
- package ex;
-
- import java.math.*;
-
- public class BigDecimalDemo {
- public static void main(String[] args){
- System.out.println(ArithUtil.add(0.01, 0.05));
- System.out.println(ArithUtil.sub(1.0, 0.42));
- System.out.println(ArithUtil.mul(4.015, 100));
- System.out.println(ArithUtil.div(123.3, 100));
- }
- }
-
- class ArithUtil{
- private static final int DEF_DIV_SCALE=10;
-
- private ArithUtil(){}
- //精確的加法算法
- public static double add(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.add(b2).doubleValue();
-
- }
- //精確的減法算法
- public static double sub(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.subtract(b2).doubleValue();
-
- }
- //精確的乘法算法
- public static double mul(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.multiply(b2).doubleValue();
-
- }
- //相對精確的除法運算,當發生除不盡的狀況時,精確到小數點之後10位
- public static double div(double d1,double d2){
-
- return div(d1,d2,DEF_DIV_SCALE);
-
- }
- //相對精確的除法運算,當發生除不盡的狀況時,精確到小數點之後指定精度(scale),再日後的數字四捨五入
- public static double div(double d1,double d2,int scale){
- if(scale<0){
- throw new IllegalArgumentException("The scale must be a positive integer or zero");
- }
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
-
- }
-
- }
運行結果以下:
說明:
雖然BigDecimal類的構造方法不少,可是咱們只使用了帶String類型的構造函數。
一、BigDecimal(double val):構造函數的結果有必定的不可預知性,好比 new BigDecimal(0.1)可能認爲就是0.1,可是實際上可能等於0.10000000006642423,這是由於0.1沒法準確地表示double
二、
BigDecimal(String val):構造函數是徹底能夠預知的。 new BigDecimal("0.1")建立的BigDecimal,正好等於預期的0.1