BigDecimal setScale ROUND_HALF_UP似乎不对每个数字进行操作

BigDecimal setScale ROUND_HALF_UP don't seem to operate on each number

提问人:Younes 提问时间:6/17/2022 最后编辑:Mark RotteveelYounes 更新时间:6/17/2022 访问量:391

问:

当我用比例 2 ROUND_HALF_UP 10.12445 时,我希望得到 10.13,因为 10.12445 -> 10.1245 -> 10.125 -> 10.13 但结果是 10.12

BigDecimal b = new BigDecimal("10.12445");
b = b.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("10.12445 scale 2 : " + b);  // 10.12

因此,如果我成功地用 4、3 和 2 的比例进行四舍五入,我会得到我期望的结果:

BigDecimal a = new BigDecimal("10.12445");
a = a.setScale(4, BigDecimal.ROUND_HALF_UP);
System.out.println("10.12445 scale 4 : " + a); //10.1245
a = a.setScale(3, BigDecimal.ROUND_HALF_UP);
System.out.println("10.1245 scale 3 : " + a); //10.125
a = a.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("10.125 scale 2 : " + a); //10.13

我错过了什么吗?

有没有办法直接得到我期望的结果?

java 精度 bigdecimal

评论

2赞 Sweeper 6/17/2022
使用计算器。10.12445 显然更接近 10.12 而不是 10.13。舍入模式是半上、半下还是半偶数甚至都无关紧要。 不实现您的“预期”舍入模式,无论该模式是什么。BigDecimal
0赞 Mark Rotteveel 6/17/2022
你对四舍五入的期望很奇怪,而且绝对是非常规的。
0赞 Younes 6/18/2022
这两个结果不同不会打扰您,我的意思是我要求 java 舍入 10.12445,而不是 124。我希望对 2 比例的四舍五入与连续四舍五入的结果相同
0赞 Mark Rotteveel 6/18/2022
Java 所做的四舍五入是绝对正常的,我希望你能展示一个用例,在这个用例中,你所期望的结果是可以接受的,甚至是需要的。

答:

0赞 Mike 'Pomax' Kamermans 6/17/2022 #1

它正在做它应该做的事情:使用比例 2 意味着“根据移动小数点后的数字对这个数字进行四舍五入”。所以我们有 10.12445,我们将其视为 1012.445 并应用HALF_UP舍入。1012.445 小于 1012.5,因此它向下舍入 1012,从而得到 10.12

根据文档:

返回一个 BigDecimal,其小数位数为指定值,其未缩放值的确定方法是将此 BigDecimal 的未缩放值乘以 10 的适当幂以保持其总值。

1赞 Sweeper 6/17/2022 #2

HALF_UP

舍入模式向“最近邻”舍入,除非两者都 邻居是等距的,在这种情况下是四舍五入的。表现为丢弃的分数≥ 0.5;否则 的行为与 .RoundingMode.UPRoundingMode.DOWN

这种四舍五入模式向最近的邻居四舍五入,只有当邻居同样接近时,我们才会做一些不同的事情。对于刻度 2,10.12445 的邻居是 10.12 和 10.13。哪个更近?它们是否同样接近?

10.13 - 10.12445 = 0.00555
10.12445 - 10.12 = 0.00445

显然 10.12 更近了,所以这就是结果。

您正在寻找的那种舍入似乎正在重复应用,一次四舍五入一个小数位,直到比例为 2:HALF_UP

var number = new BigDecimal("10.12445");
for (int i = number.scale() ; i >= 2 ; i--) {
    number = number.setScale(i, RoundingMode.HALF_UP);
}

这是一种相当奇怪的四舍五入方式,并给出了一些不直观(至少对我来说)的结果。