BigDecimal類


BigDecimal 是java小數操做的一個專有類,在電商、金融行業 存儲跟金額有關的字段java

java裏面明明已經有了,float,double這種精度的小數,爲何還須要BigDecimal呢?
這難道不是多餘嗎?ide

接下來看一個例子:函數

1 @Test
2 public void testDoubleSimple() {
3 double a = 3;
4 double b = 10;
5 double c = a / b;
6 System.out.println(c);
7 }

控制檯輸出:0.3this

在小數操做中,咱們一般但願能有多種自由的定義方式。spa

例如在不一樣的場景可能須要返回: 0.3, 0.4, 0.333 不一樣精度,在不一樣的精度進位時但願能自主控制.net

這個時候,就輪到BigDecimal出場了code

加減乘除
首先來一段最簡單的加減乘除blog

 1 @Test
 2 public void testDecimalSimple() {
 3 BigDecimal a = new BigDecimal(5);
 4 BigDecimal b = new BigDecimal(40);
 5 BigDecimal add = a.add(b);
 6 BigDecimal subtract = a.subtract(b);
 7 BigDecimal multiply = a.multiply(b);
 8 BigDecimal divide = a.divide(b);
 9 System.out.println("add:" + add);
10 System.out.println("subtract:" + subtract);
11 System.out.println("multiply:" + multiply);
12 System.out.println("divide:" + divide);
13 }

控制檯輸出內容以下:ip

add:45;
subtract:-35;
multiply:200;
divide:0.125;

在瞭解了BigDecimal基本內容後,在去深刻的去使用它的精度內存

精度控制
精度有7種模式,舉例以下

 1 @Test
 2 public void testRound() {
 3 // 正無窮大方向取整
 4 System.out.println("celling:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.CEILING)));
 5 // 負無窮大方向取整
 6 System.out.println("floor:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.FLOOR)));
 7 //向 0 的方向取整
 8 System.out.println("down a:" + new BigDecimal(0.121, new MathContext(2, RoundingMode.DOWN)));
 9 System.out.println("down b:" + new BigDecimal(-0.129, new MathContext(2, RoundingMode.DOWN)));
10 // 正數向正無窮大取整,負數向負無窮大取整
11 System.out.println("up a:" + new BigDecimal(0.121, new MathContext(2, RoundingMode.UP)));
12 System.out.println("up b:" + new BigDecimal(-0.129, new MathContext(2, RoundingMode.UP)));
13 /**
14 * 5,6,7,8,9 向上取整
15 * 1,2,3,4 向下取整
16 *
17 * 經常使用的4舍5入
18 */
19 System.out.println("half up:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.HALF_UP)));
20 /**
21 * 6,7,8,9 向上取整
22 * 1,2,3,4,5 向下取整
23 *
24 * 5 向下取整
25 */
26 System.out.println("half down:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.HALF_DOWN)));
27 
28 /**
29 * 小數位是5時,判斷整數部分是奇數就進位
30 * 1,2,3,4, 捨棄
31 * 6,7,8,9, 進位
32 */
33 System.out.println("odd a:" + new BigDecimal(5.4, new MathContext(1, RoundingMode.HALF_EVEN)));
34 System.out.println("odd b:" + new BigDecimal(5.5, new MathContext(1, RoundingMode.HALF_EVEN)));
35 /**
36 * 小數位是5時,判斷整數部分是偶數就捨棄
37 * 1,2,3,4, 捨棄
38 * 6,7,8,9, 進位
39 */
40 System.out.println("even a:" + new BigDecimal(6.5, new MathContext(1, RoundingMode.HALF_EVEN)));
41 System.out.println("even b:" + new BigDecimal(6.6, new MathContext(1, RoundingMode.HALF_EVEN)));
42 }

控制檯輸出內容以下

celling:0.13;
floor:0.12;
down a:0.12;
down b:-0.12;
up a:0.13;
up b:-0.13;
half up:0.13;
half down:0.12;
odd a:5;
odd b:6;
even a:6;
even b:7;

在 RoundingMode.XXXXX 類型的源碼註釋上面,有更加詳細的例子,能夠看到是怎麼舍入的

除法詳細介紹

我認爲在電商,金融領域中,用BigDecimal最重要的緣由有兩個:
1. 精度準確
2. 除法運算支持好

因此必定要對除法作深刻的瞭解,作項目的時候,才能不會對這些類型感到疑惑

1 @Test
2 public void testDecimalDivide() {
3 BigDecimal a = new BigDecimal(5.4);
4 BigDecimal b = new BigDecimal(3.1);
5 BigDecimal divide = a.divide(b);
6 System.out.println("divide:" + divide);
7 }

出現異常:
 1 java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 

明明剛剛還好好的,怎麼如今出了事?

那是由於 5.四、3.1都是double類型轉換的 BigDecimal。

實際上5.4在內存中多是 5.40000003321546546 的內容。致使BigDecimal內部精度計算的時候,發生錯誤

這個錯誤是由於沒有指定精度致使的,咱們只要指定告終果的精度,就能夠避免這個問題。

推薦作法

 1 @Test
 2 public void testDecimalStandDivide() {
 3 BigDecimal a = new BigDecimal(5.4);
 4 BigDecimal b = new BigDecimal(3.1);
 5 // 保留幾位小數
 6 int scale = 2;
 7 // 重點:務必是3個參數
 8 BigDecimal divide = a.divide(b,scale,RoundingMode.HALF_UP);
 9 System.out.println("divide:" + divide);
10 
11 }

 

控制檯輸出:divide:1.74

咱們額外傳入第二個參數:保留的小數,指定告終果的精度,就能夠避免出現這種問題。

因此咱們平常用BigDecimal作除法運算的時候,務必寫成推薦的形式。避免出現了異常,本身還莫名其妙

默認除法精度
在文章的開頭的除法,是用整數轉成BigDecimal, 保留的3爲小數。 那默認狀況下會精確到幾位呢?

在跟進到divide函數內部時,發現了構造MathContext的部份內容:

1 MathContext mc = new MathContext( (int)Math.min(this.precision() +
2 (long)Math.ceil(10.0*divisor.precision()/3.0),
3 Integer.MAX_VALUE),
4 RoundingMode.UNNECESSARY);

整數 12345 的precision 是5
整數 332 的precision 是 3
小數5.4 的precision多是 5.40000065464698656565454454555 的長度。 值不固定

根據MathContext的第一個參數的計算方式獲得默認除法精度:
1. 當被除數爲:0x1 最低精度5
2. 當被除數爲:0xFFFFFFFF 最高精度36

總結

BigDecimal 精度描述:

模式 描述
CEILING 正無窮大方向取整
FLOOR 負無窮大方向取整
DOWN 向 0 的方向取整
UP 正數向正無窮大取整,負數向負無窮大取整
HALF_UP 5,6,7,8,9 向上取整、 1,2,3,4 向下取整、 經常使用的4舍5入
HALF_DOWN 6,7,8,9 向上取整 1,2,3,4,5 向下取整
HALF_EVEN 小數位是5時,判斷整數部分是奇數就進位、 小數位是5時,判斷整數部分是偶數就捨棄、 1,2,3,4, 捨棄、 6,7,8,9, 進位

 

        ————————————————參考連接:https://blog.csdn.net/mz4138/article/details/82708815

相關文章
相關標籤/搜索