float和double類型一般用於科學計算,BigDecimal由於擁有完全精確的結果,所以商業計算往往使用BigDecimal
在需要精確度的項目不適用float和double的原因
代碼:
System.out.println(0.2 + 0.1);
System.out.println(0.3 - 0.1);
System.out.println(0.2 * 0.1);
System.out.println(0.3 / 0.1);
運行結果:
0.30000000000000004
0.19999999999999998
0.020000000000000004
2.9999999999999996
結論:由於我們的計算機是二進制的。浮點數沒有辦法是用二進制進行精確表示。我們的CPU表示浮點數由兩個部分組成:指數和尾數,這樣的表示方法一般都會失去一定的精確度,有些浮點數運算也會產生一定的誤差。如:2.4的二進制表示並非就是精確的2.4。反而最為接近的二進制表示是 2.3999999999999999。浮點數的值實際上是由一個特定的數學公式計算得到的。
BigDecimal構造方法
- public BigDecimal(double val)
- public BigDecimal(int val)
- public BigDecimal(long val)
- public BigDecimal(String val)
- public BigDecimal(char[] val)
- public BigDecimal(BigInteger val)
在構造方法中不推薦使用double
-
當BigDecimal傳參為
BigDecimal bDouble = new BigDecimal(2.3);
時,結果為bDouble=2.29999999999999982236431605997495353221893310546875
所以參數類型為double的構造方法的結果有一定的不可控性。實際上的值不一定等於你想要的值。 -
String 構造方法是完全可控的:在newBigDecimal("0.1") 中創建一個 BigDecimal,它的值為0.1。因此通常建議優先使用String構造方法。
BigDecimal加減乘除
- public BigDecimal add(BigDecimal value); 加法
- public BigDecimal subtract(BigDecimal value); 減法
- public BigDecimal multiply(BigDecimal value); 乘法
- public BigDecimal divide(BigDecimal value); 除法
示例代碼:
BigDecimal a = new BigDecimal("3.2");
BigDecimal b = new BigDecimal("2.3");
BigDecimal add = a.add(b);
BigDecimal subtract = a.subtract(b);
BigDecimal multiply = a.multiply(b);
BigDecimal divide = a.divide(b,2,RoundingMode.HALF_UP);
System.out.println("a + b ="+add);
System.out.println("a - b ="+subtract);
System.out.println("a * b ="+multiply);
System.out.println("a / b +"+divide);
結果:
a + b =5.5
a - b =0.9
a * b =7.36
a / b +1.39
加減乘法
MathContext構造器
MathContext(int setPrecision, RoundingMode setRoundingMode)
- setPrecision:小數點幾位
- setRoundingMode:舍入模式
可以通過mathContext來改變精度和舍入模式
BigDecimal a = new BigDecimal("3.2");
BigDecimal b = new BigDecimal("2.3");
MathContext mathContext = new MathContext(2,RoundingMode.HALF_UP);
BigDecimal multiply = a.multiply(b,mathContext);
除法divide
我們需要注意的是如果我們的參數只填寫被除數,除后的結果不是整數就會報錯
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1693)
at com.demos.date.date01.main(date01.java:30)
解決方法:
完善構造參數
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
參數解釋:
- divisor:除數
- scale:表示小數點保留位數
- roundingMode:表示舍入模式
舍入模式roundingMode
我們一般舍入模式采取的是ROUND_HALF_UP
- ROUND_CEILING //向正無窮方向舍入
BigDecimal a = new BigDecimal("0.098").setScale(2, BigDecimal.ROUND_CEILING); // 0.10
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_CEILING); // 0.10
BigDecimal c = new BigDecimal("-0.098").setScale(2, BigDecimal.ROUND_CEILING); // -0.09
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_CEILING); // -0.09
BigDecimal e = new BigDecimal("-0.090").setScale(2, BigDecimal.ROUND_CEILING); // -0.09
BigDecimal f = new BigDecimal("0.090").setScale(2, BigDecimal.ROUND_CEILING); // 0.09
- ROUND_UP //不管保留數字后面是大是小 (0 除外) 都會進1。
BigDecimal a = new BigDecimal("0.095").setScale(2, BigDecimal.ROUND_HALF_UP); // 0.10
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_HALF_UP); // 0.09
BigDecimal c = new BigDecimal("-0.095").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.10
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.09
BigDecimal e = new BigDecimal("-0.090").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.09
BigDecimal f = new BigDecimal("-0.098").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.10
- ROUND_DOWN //舍去制,截斷操作,后面所有數字直接去除。結果會向原點方向對齊
BigDecimal a = new BigDecimal("0.098").setScale(2, BigDecimal.ROUND_DOWN); // 0.09
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_DOWN); // 0.09
BigDecimal c = new BigDecimal("-0.098").setScale(2, BigDecimal.ROUND_DOWN); // -0.09
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_DOWN); // -0.09
BigDecimal e = new BigDecimal("-0.090").setScale(2, BigDecimal.ROUND_DOWN); // -0.09
BigDecimal f = new BigDecimal("0.090").setScale(2, BigDecimal.ROUND_DOWN); // 0.09
- ROUND_FLOOR //向負無窮方向舍入
BigDecimal a = new BigDecimal("0.098").setScale(2, BigDecimal.ROUND_FLOOR); // 0.09
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_FLOOR); // 0.09
BigDecimal c = new BigDecimal("-0.098").setScale(2, BigDecimal.ROUND_FLOOR); // -0.10
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_FLOOR); // -0.10
BigDecimal e = new BigDecimal("-0.090").setScale(2, BigDecimal.ROUND_FLOOR); // -0.09
BigDecimal f = new BigDecimal("0.090").setScale(2, BigDecimal.ROUND_FLOOR); // 0.09
- ROUND_HALF_EVEN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,如果保留位數是奇數,使用ROUND_HALF_UP,如果是偶數,使用ROUND_HALF_DOWN
BigDecimal a = new BigDecimal("0.095").setScale(2, BigDecimal.ROUND_HALF_EVEN); // 0.10
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_HALF_EVEN); // 0.09
BigDecimal c = new BigDecimal("-0.095").setScale(2, BigDecimal.ROUND_HALF_EVEN); // -0.10
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_HALF_EVEN); // -0.09
BigDecimal e = new BigDecimal("-0.085").setScale(2, BigDecimal.ROUND_HALF_EVEN); // -0.08
BigDecimal f = new BigDecimal("-0.084").setScale(2, BigDecimal.ROUND_HALF_EVEN); // -0.08
BigDecimal g = new BigDecimal("-0.086").setScale(2, BigDecimal.ROUND_HALF_EVEN); // -0.09
- ROUND_HALF_UP //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入, 1.55保留一位小數結果為1.6
BigDecimal a = new BigDecimal("0.095").setScale(2, BigDecimal.ROUND_HALF_UP); // 0.10
BigDecimal b = new BigDecimal("0.094").setScale(2, BigDecimal.ROUND_HALF_UP); // 0.09
BigDecimal c = new BigDecimal("-0.095").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.10
BigDecimal d = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.09
BigDecimal e = new BigDecimal("-0.090").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.09
BigDecimal f = new BigDecimal("-0.098").setScale(2, BigDecimal.ROUND_HALF_UP); // -0.10
- ROUND_HALF_DOWN //向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入, 例如1.55 保留一位小數結果為1.5
BigDecimal a = new BigDecimal("0.096").setScale(2, BigDecimal.ROUND_HALF_DOWN); // 0.10
BigDecimal b = new BigDecimal("0.095").setScale(2, BigDecimal.ROUND_HALF_DOWN); // 0.09
BigDecimal c = new BigDecimal("-0.096").setScale(2, BigDecimal.ROUND_HALF_DOWN); // -0.10
BigDecimal d = new BigDecimal("-0.095").setScale(2, BigDecimal.ROUND_HALF_DOWN); // -0.09
BigDecimal e = new BigDecimal("-0.094").setScale(2, BigDecimal.ROUND_HALF_DOWN); // -0.09
- ROUND_UNNECESSARY //計算結果是精確的,不需要舍入模式
BigDecimal g = new BigDecimal("-0.086").setScale(2, BigDecimal.ROUND_UNNECESSARY);
減乘除最終都返回的是一個新的BigDecimal對象,因為BigInteger與BigDecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生一個新的對象
代碼示例
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
a.add(b);
System.out.println(a); //輸出4.5. 加減乘除方法會返回一個新的BigDecimal對象,原來的a不變