简体   繁体   English

使用 DecimalFormat 的 RoundingMode.UP 无法按预期工作

[英]RoundingMode.UP with DecimalFormat does not work as expected

I'm trying to round up a Double number whenever there is a decimal value.每当有十进制值时,我都会尝试将 Double 数字四舍五入。 I'm trying the below.我正在尝试以下。 The below snippet is rounding up all other values as expected.下面的代码片段按预期四舍五入所有其他值。

1.08 -> 2
9.5 -> 10

but rounds 0.08 as 0 instead of 1. Am I missing something here?但将 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

This looks like a manifestation of bug JDK-8174722 , reported for JDK8, and still open with a fix version "tbd" (I see the same behavior on JDK14).这看起来像是针对 JDK8 报告的错误 JDK-8174722的表现,并且仍然以修复版本“tbd”打开(我在 JDK14 上看到了相同的行为)。 In that bug report, rounding up 0.0001 to two fewer decimal places incorrectly results in 0.00 rather than 0.01 .在该错误报告中,将0.0001向上舍入到小数点后两位会错误地导致0.00而不是0.01

I tried to trace this calculation through the source code of DecimalFormat and found multiple assumptions on numbers of significant digits, retained for compatibility but apparently the cause of issues like this.我试图通过DecimalFormat的源代码来跟踪这个计算,并发现了关于有效数字的多个假设,为了兼容性而保留,但显然是此类问题的原因。 My hunch based on the source code is that if the first digit after the requested precision is 0 (or close enough) the function rounds down.我基于源代码的预感是,如果请求精度之后的第一个数字为 0(或足够接近),则 function 向下舍入。 This behavior is contrary to the documentation which clearly states otherwise.这种行为与明确说明的文档相反。

If it were easy to fix, I gather the linked bug would have been fixed long before now, but it also appears to be a low priority.如果它很容易修复,我认为链接的错误早就被修复了,但它似乎也是一个低优先级。

As the comments have suggested, using Math.ceil() , Math.floor() , and Math.round() functions would provide more predictable/consistent results and suffice for most use cases.正如评论所建议的那样,使用Math.ceil()Math.floor()Math.round()函数将提供更多可预测/一致的结果,并且足以满足大多数用例。

In your comments, you suggested the user provided the RoundingMode , so if you want a direct application of that enum, the bug report's MCVE includes a workaround using BigDecimal.setScale() .在您的评论中,您建议用户提供RoundingMode ,因此如果您想要直接应用该枚举, 错误报告的 MCVE包含使用BigDecimal.setScale()的解决方法。 @Andreas posted an application of this workaround in this comment to produce this string: @Andreas此评论中发布了此解决方法的应用程序以生成此字符串:

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

Another option using a DecimalFormat would allow changing Locale settings and would be:使用DecimalFormat的另一个选项将允许更改区域设置,并且是:

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

Note that since you would use the rounding up in setScale() you do not need to also use it in the DecimalFormat .请注意,由于您将在setScale()中使用四舍五入,因此您不需要在DecimalFormat中也使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM