4castle 4castle - 6 months ago 20
Java Question

DecimalFormat using incorrect RoundingMode even when set explicitly

Why is this

DecimalFormat
not rounding using
RoundingMode.HALF_UP
as expected, and what should be done to get the expected output? Can it be done with
DecimalFormat
?

DecimalFormat df = new DecimalFormat("0.0");

df.setRoundingMode(RoundingMode.HALF_UP);

df.format(0.05); // expecting 0.1, getting 0.1
df.format(0.15); // expecting 0.2, getting 0.1 << unexpected

df.format(0.06); // expecting 0.1, getting 0.0 << unexpected


I have seen the answers from this question, specifically this answer, but it only seems to work when rounding to an integer.

My JDK is 8.0.110 and my JRE is 8.0.730.2

Answer

(Answer below using Java 8.)

The issue you are seeing comes from specifying "0.15" or "0.05" in code, which when represented as a double is something slightly less than 0.15. Check this out

DecimalFormat df = new DecimalFormat("#.#");

df.setRoundingMode(RoundingMode.HALF_UP);

BigDecimal bd = new BigDecimal(0.15);
System.out.println("bd=" + bd);
System.out.println(df.format(0.15)); // expecting 0.1, getting 0.1
bd = new BigDecimal(0.05);
System.out.println("bd=" + bd);
System.out.println(df.format(0.05));
bd = new BigDecimal(0.06);
System.out.println("bd=" + bd);
System.out.println(df.format(0.06));

The output of this code is

bd=0.1499999999999999944488848768742172978818416595458984375
0.1
bd=0.05000000000000000277555756156289135105907917022705078125
0.1
bd=0.059999999999999997779553950749686919152736663818359375
0.1

A possible solution (if you absolutely need it to round the right way) is to use BigDecimal.valueOf to create the value. For example

BigDecimal bd = BigDecimal.valueOf(0.15);
System.out.println("bd=" + bd);
System.out.println(df.format(bd)); // expecting 0.1, getting 0.1
bd = BigDecimal.valueOf(0.05);
System.out.println("bd=" + bd);
System.out.println(df.format(bd));
bd = BigDecimal.valueOf(0.06);
System.out.println("bd=" + bd);
System.out.println(df.format(bd));

Will now yield

bd=0.15
0.2
bd=0.05
0.1
bd=0.06
0.1

BTW, as Scary Wombat pointed out, the mask set as 0.0 instead of #.# will make 0.6 0. But I think that was a later edit then when I started looking at it. Use #.#.