1、问题复现
在利用BigDecimal进行精确计算时,在divide()方法会出现Non-terminating decimal expansion; no exact representable decimal result.的问题。如下图:
BigDecimal a = new BigDecimal("460146.388995");
BigDecimal b = new BigDecimal("626.0625");
System.err.println(a.divide(b));
此时由于a/b的结果是无限不循环的小数,而BigDecimal要求是精确计算,所以需要设置舍入模式解决以上问题。
选择了通过setScale()方法对结果进行取舍。
System.err.println("通过setScale对结果进行舍入"+a.divide(b).setScale(2,BigDecimal.ROUND_HALF_UP));
但还是出现了以上问题,如下图:
但是明明设置了setScale去做取舍,但是为什么没有生效呢?
然后看了一下对setScale()方法的解释,如下图:
看不懂?没关系,大致的意思是setSacle()方法是对商进行取舍的。当商是无限不循环的小数,结果就不符合BigDecimal的定义,setScale()方法就不会执行。
2、问题修改
此时注意到了divide()方法上被阴影覆盖,故鼠标放上之后可以看到一下信息,如下图:
修改后:
System.err.println("在除法操作上舍入=========>"+a.divide(b,2,BigDecimal.ROUND_HALF_UP));
结果正确,同时阴影消失。
3、对比
public class Example2 {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("460146.388995");
BigDecimal b = new BigDecimal("626.0625");
BigDecimal c = new BigDecimal("3.755");
BigDecimal d = new BigDecimal("5");
System.err.println("在除法操作上舍入=========>"+a.divide(b,2,BigDecimal.ROUND_HALF_UP));
System.err.println("结果是可被整除的,通过setScale舍入=========>"+ c.divide(d).setScale(2,BigDecimal.ROUND_HALF_UP));
System.err.println("通过setScale对结果进行舍入"+a.divide(b).setScale(2,BigDecimal.ROUND_HALF_UP));
}
}
结果如下:
可以看到 第一二行打印可以正常输出,第三行报错。
4、总结
当通过BigDecimal进行除法运算时,需要注意divide(param1,param2,param3)有三个参数,参数1是除数,参数2是newScale --要返回的BigDecimal值的刻度,参数3是roundingMode --要应用的舍入模式;setScale(param1,param2)参数2是newScale--要返回的BigDecimal值的刻度,参数3是roundingMode --要应用的舍入模式。
舍入模式有以下几种:
RoundingMode | 说明 | 举例(scale = 2) |
不设置取舍模式 | 没有舍入模式:11.57131 / 5 = 2.314262 | |
ROUND_UP | 根据scale值向上取整,远离0值,总是将被丢弃的非零分数前的数字加1。故结果 >= 值 | ROUND_UP: 11.57131 / 5 = 2.31427 |
ROUND_DOWN | 根据scale值向下取整,趋近0值。可以理解为根据scale值对结果截断,故结果 <= 值 | ROUND_DOWN: 11.57131 / 5 = 2.31426 |
ROUND_CEILING | 舍入模式向正无穷大舍入。如果BigDecimal为正数,则表现为ROUND_UP;如果为负值,则表现为ROUND_DOWN。注意,这种舍入模式永远不会减少计算值。 | ROUND_CEILING:11.57131 / 5 = 2.31427 |
ROUND_FLOOR | 舍入模式向负无穷大舍入。如果BigDecimal为正数,则表现为ROUND_DOWN;如果是否定的,就像ROUND_UP一样。注意,这种舍入模式不会增加计算值。 | ROUND_FLOOR: 11.57131 / 5 = 2.31426 |
ROUND_HALF_UP | 四舍五入 | ROUND_HALF_UP:11.57131 / 5 = 2.31426 |
ROUND_HALF_DOWN | 舍入模式向“最近邻居”舍入,除非两个邻居距离相等,在这种情况下舍入向下。如果丢弃的分数> 0.5,则表现为ROUND_UP;否则,行为与ROUND_DOWN相同。 | ROUND_HALF_DOWN:11.57131 / 5 = 2.31426 |
ROUND_HALF_EVEN | 舍入模式向“最近的邻居”舍入,除非两个邻居都等距,在这种情况下,向偶数邻居舍入。如果舍弃分数左边的数字为奇数,则表现为ROUND_HALF_UP;如果是偶数,则其行为与ROUND_HALF_DOWN相同。请注意,这是舍入模式,当在一系列计算中重复应用时,该模式可将累积误差最小化 | ROUND_HALF_EVEN:11.57131 / 5 = 2.31426 |
ROUND_UNNECESSARY | 舍入模式可以断言所请求的操作具有准确的结果,因此不需要舍入。如果在产生不精确结果的操作上指定了这种舍入模式,则会引发ArithmeticException |