看一下下边的代码:
@Testpublic void calTest() {BigDecimal realGmv = BigDecimal.valueOf(30598.0);BigDecimal gmvTarget = BigDecimal.valueOf(275800.00);int assessDayCnt = 15;int periodDayCnt = 30;BigDecimal middle = realGmv.multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(assessDayCnt)).divide(BigDecimal.valueOf(periodDayCnt), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);BigDecimal ratio = middle.divide(gmvTarget, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);System.out.println(middle);System.out.println(ratio);BigDecimal middle2 = realGmv.multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(assessDayCnt)).divide(BigDecimal.valueOf(periodDayCnt), RoundingMode.HALF_UP);BigDecimal ratio2 = middle2.divide(gmvTarget, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);System.out.println(middle2);System.out.println(ratio2);BigDecimal middle3 = gmvTarget.multiply(BigDecimal.valueOf(periodDayCnt));BigDecimal ratio3 = realGmv.multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(assessDayCnt)).divide(middle3, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);System.out.println(middle3);System.out.println(ratio3);}
这三种计算方法的输出是:
1529900.00
5.55
1529900.0
5.50
8274000.0
5.50
最终输出结果大相径庭,最根本的原因就是后两种计算方式中,中间的被除数的精度是小数点后一位,BigDecimal在做除法运算的时候有一个保留位数的规则:
BigDecimal 除法规则:结果 scale = max(被除数.scale() - 除数.scale(), 0) + 1
所以后两种其实是divide的时候结果算出来时5.547-》保留一位变成5.5然后setScale生效,补一个0变成5.50。
第一种写法恰好对也是因为第一次是一个整除,所以直接setScale没问题,假如不是整除也会有问题。
最简单的解决办法就是在divide的方法里加上结果位数的指定,比如下边:
BigDecimal middle4 = realGmv.multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(assessDayCnt)).divide(BigDecimal.valueOf(periodDayCnt), 10, RoundingMode.HALF_UP);BigDecimal ratio4 = middle2.divide(gmvTarget, 10, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);System.out.println(middle4);System.out.println(ratio4);
随后在加上setScale就不会有问题了。简直不要太隐蔽。。。。