舍入模式.UP 与十进制格式无法按预期工作

2022-09-04 03:50:31

我试图在有十进制值时舍入双精度值。我正在尝试以下方法。下面的代码段按预期对所有其他值进行舍入。

1.08 -> 2
9.5 -> 10

但将 0.08 舍入为 0 而不是 1。我在这里错过了什么吗?

DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.UP);
Double number = 0.08;
System.out.println(df.format(number)); // expecting 1 but produces 0
    
number = 1.08;
System.out.println(df.format(number)); // correctly produces 2

答案 1

这看起来像是针对 JDK8 报告的错误 JDK-8174722 的表现,并且仍然以修复版本“tbd”打开(我在 JDK14 上看到相同的行为)。在该 bug 报告中,最多将小数点后两位舍入错误地导致 而不是 。0.00010.000.01

我试图通过源代码来跟踪此计算,并发现了对有效数字数的多个假设,保留这些假设是为了兼容性,但显然是导致此类问题的原因。根据源代码,我的直觉是,如果请求的精度后的第一个数字为0(或足够接近),则函数将向下舍入。此行为与明确说明的文档相反。DecimalFormat

如果它很容易修复,我收集链接的错误早就已经修复了,但它似乎也是一个低优先级。

正如注释所建议的那样,使用 、 和 函数将提供更可预测/更一致的结果,并且足以满足大多数用例。Math.ceil()Math.floor()Math.round()

在您的注释中,您建议用户提供 ,因此,如果您希望直接应用该枚举,则错误报告的 MCVE 包括使用 的解决方法。@Andreas在此评论中发布了此变通办法的应用以生成此字符串:RoundingModeBigDecimal.setScale()

// Note: this ignores Locale
BigDecimal.valueOf(number).setScale(0, RoundingMode.UP).toPlainString();

使用的另一个选项将允许更改区域设置,并且是:DecimalFormat

df.format(BigDecimal.valueOf(number).setScale(0, RoundingMode.UP));

请注意,由于您将在 中使用舍入,因此不需要在 中也使用它。setScale()DecimalFormat


答案 2