BigDecimal除法小坑并解决

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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值