这是使用 BigDecimals 舍入的正确行为吗?

Is this the correct behavior for rounding with BigDecimals?

我试图像这样舍入 BigDecimals:5.46597 -> 5.46,我认为下面的代码为我做了这个,但不是。

我用 BigDecimal.round 和 BigDecimal.setScale 试过了。

BigDecimal bD = new BigDecimal(5.46597); // whole number: 5.4659700000000004393996277940459549427032470703125 
bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47
bD.round(new MathContext(3, RoundingMode.HALF_DOWN)); // 5.47

这不是应该是5.46吗,还是我理解错了什么?

使用 ROUND_HALF_DOWN 使用 BigDecimal 进行舍入在 JavaDoc 中定义为“ROUND_HALF_DOWN - 舍入模式向 "nearest neighbor" 舍入,除非两个邻居是等距的,在这种情况下向下舍入。" Documentation ROUND_HALF_DOWN Documentation RoundingMode.HALF_DOWN

对于 BigDecimal.valueOf("5.46597").setScale(2, BigDecimal.ROUND_HALF_DOWN),最近的邻居是 5.465.47,距离为 0.005970.00403。 所以到 5.47 的距离比到 5.46 的距离更小(更近),这导致四舍五入到 5.47.

HALF_DOWN 仅当实际值恰好位于两个可能的舍入值的中间时才向下舍入。 IE。 5.46500 -> 5.46。另一方面,5.4650000001 -> 5.47,因为它比 5.46 更接近 5.47。

也许您要查找的是 RoundingMode.DOWN,它总是向下舍入。

第一:使用double值的构造函数,立即引入每个浮点数的逼近误差

正在使用

BigDecimal bD = new BigDecimal("5.46597");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47

BigDecimal bD = new BigDecimal("5.46500");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.46

一个人得到一个有 5 位小数的精确定点数。

HALF_DOWN 在 .500000 上四舍五入...不多,只是 5er 边界。

Logical rounding will happen to its nearest integer, above a half will be rounded up, below a half will round be rounded down. On the exact half the international math standard says: round up, but logically (the same distance) it can be either: HALF_UP or HALF_DOWN. As the effect only relates to the exact half, testing should not be done with a double constructor, that probably yields a value a tiny bit above or below the exact half.

你也忘记了作业

当截断部分 > 0.5 时,

RoundingMode.HALF_DOWN 和 RoundingMode.HALF_UP 的工作方式相同,例如这里,

BigDecimal bD = new BigDecimal(5.46597);
bD.setScale(2, RoundingMode.HALF_DOWN);//5.47
bD.setScale(2, RoundingMode.HALF_UP; //5.47

因为小数点后2位截断部分(597)->0.597大于0.5。 这就是 HALF_DOWN

规范所说的

"Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. Behaves as for RoundingMode.UP if the discarded fraction is > 0.5; otherwise, behaves as for RoundingMode.DOWN."

如果您的需求如下

BigDecimal bD = new BigDecimal(5.46597);
bD.setScale(2, RoundingMode.HALF_DOWN);//5.46

然后使用@Balázs Sipos 自己建议的下面一行。

bD.setScale(3, RoundingMode.DOWN).setScale(2, RoundingMode.HALF_DOWN);
//first part would give 5.465 then the second part would produce 5.46

应该可以。干杯!