# RoundingMode.UP 与 DecimalFormat 结合使用不如预期那样工作。

go评论48阅读模式

RoundingMode.UP with DecimalFormat does not work as expected

# 问题

1.08 -> 2
9.5 -> 10

DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.UP);
Double number = 0.08;
System.out.println(df.format(number)); // 期望为1，但产生0

number = 1.08;
System.out.println(df.format(number)); // 正确地产生2

I'm trying to round up a Double number whenever there is a decimal value. I'm trying the below.
The below snippet is rounding up all other values as expected.

``````1.08 -&gt; 2
9.5 -&gt; 10
``````

but rounds 0.08 as 0 instead of 1. Am I missing something here?

``````DecimalFormat df = new DecimalFormat(&quot;0&quot;);
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

// 注意：这忽略了Locale
BigDecimal.valueOf(number).setScale(0, RoundingMode.UP).toPlainString();

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

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). In that bug report, rounding up `0.0001` to two fewer decimal places incorrectly results in `0.00` rather than `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. 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. 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.

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()`. @Andreas posted an application of this workaround in this comment to produce this string:

``````// 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:

``````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`.

• 本文由 发表于 2020年8月2日 00:53:14
• 转载请务必保留本文链接：https://go.coder-hub.com/63207758.html
• double
• java
• rounding

go 47

go 48

go 35

go 36