Java BigDecimal学习

Java BigDecimal不损失精度的方法

1、调用valueOf()方法(推荐)
2、调用构造方法BigDecimal(String)

在这里插入图片描述

Java BigDecimal的几种舍入模式

1、UP(BigDecimal.ROUND_UP)

  • 向绝对值最大的方向舍入
  • 只要舍弃位非0即进位

2、DOWN(BigDecimal.ROUND_DOWN)

  • 向绝对值最小的方向输入
  • 所有的位都舍弃,不存在进位情况。

3、CEILING(BigDecimal.ROUND_CEILING)

  • 天花板数:正数变大,负数也是变大。即正得越多,负得越少。
  • 正数,只要舍弃位非0即进位,同UP。负数,所有的位都舍弃,不存在进位情况,同DOWN。
  • Math.round方法使用的即为此模式。

4、FLOOR(BigDecimal.ROUND_FLOOR)

  • 地板数:正数变小,负数也是变小。即正得越少,负得越多。
  • 正数,所有的位都舍弃,不存在进位情况,同DOWN。负数,只要舍弃位非0即进位,同UP。

5、HALF_UP(BigDecimal.ROUND_HALF_UP)

最近数字舍入(5舍)。经典的四舍五入,5是进位。

6、HALF_DOWN(BigDecimal.ROUND_HALF_DOWN)

最近数字舍入(5舍)。HALF_DOWN中5是舍弃不进位。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
// 5.5 
// 舍弃位为5,舍弃位后的数字为0
BigDecimal sum = BigDecimal.valueOf(5.550).setScale(1,BigDecimal.ROUND_HALF_DOWN);
// 5.6
// 舍弃位为5,舍弃位后的数字非0
BigDecimal sum = BigDecimal.valueOf(5.551).setScale(1,BigDecimal.ROUND_HALF_DOWN);
// 5.6
// 舍弃位为5,舍弃位后的数字非0
BigDecimal sum = BigDecimal.valueOf(5.55001).setScale(1,BigDecimal.ROUND_HALF_DOWN);
// -5.6
// 舍弃位为5,舍弃位后的数字非0
BigDecimal sum = BigDecimal.valueOf(-5.55001).setScale(1,BigDecimal.ROUND_HALF_DOWN);

7、HALF_EVEN(BigDecimal.ROUND_HALF_EVEN)

银行家算法。
四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

8、UNNECESSARY(BigDecimal.ROUND_UNNECESSARY)

断言请求的操作具有精确的结果,因此不需要舍入。
如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

示例代码:

1
2
// 抛出ArithmeticException 只有1位小数时不会报错
BigDecimal sum = BigDecimal.valueOf(-5.81).setScale(1,BigDecimal.ROUND_UNNECESSARY);

参考链接

Java BigDecimal不同模式下的舍入操作举例汇总

输入给定数字,保留1位数的结果如下:

输入数字 UP DOWN CEILING FLOOR HALF_UP HALF_DOWN
1.34 1.4 1.3 1.4 1.3 1.3 1.3
1.35 1.4 1.3 1.4 1.3 1.4 1.3
1.36 1.4 1.3 1.4 1.3 1.4 1.4
-1.34 -1.4 -1.3 -1.3 -1.4 -1.3 -1.3
-1.35 -1.4 -1.3 -1.3 -1.4 -1.4 -1.3
-1.351 -1.4 -1.3 -1.3 -1.4 -1.4 -1.4
-1.36 -1.4 -1.3 -1.3 -1.4 -1.4 -1.4

Java BigDecimal进行除法运算报异常

问题现象

执行下面的代码:

1
2
3
BigDecimal sum = new BigDecimal("777.77");
BigDecimal avg = sum.divide(new BigDecimal("15"));
System.out.println(avg);

报错:

1
2
3
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.chuenhung.Test.main(Test.java:9)

原因分析

BigDecimal进行除法运算时,准确的商可能是一个无限长的小数,如果此时没有指定舍入模式,就会报ArithmeticException。
上面的777.77除以15的结果是个无限循环小数,而没有指定舍入模式,所以报错。

解决方法

调divide(divisor, scale, roundingMode);方法,其中scale为保留位数,roundingMode为舍入模式。

1
2
// 示例
BigDecimal avg = sum.divide(new BigDecimal("15"),3,BigDecimal.ROUND_DOWN);

参考链接