j.barrio
j.barrio

Reputation: 1036

Java DecimalFormat HALF_UP rounding error

I'm using the DecimalFormat with HALF_UP rounding mode and I have an escenery where is not working correctly and I don't know why.

DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.HALF_UP);
float tmp = (float) (0.5 * 1.05);
df.format(tmp);
float mul = Float.parseFloat(df.format(tmp));

The mul variable value I hope have 0.53 value and I received 0.52 value.

I'm using the Java 1.8.0_131.

SOLVED FINAL CODE

BigDecimal mul = new BigDecimal(0.5).multiply(new igDecimal(1.05));
mul = mul.setScale(2, RoundingMode.HALF_UP);
System.out.println(mul);

Upvotes: 1

Views: 1417

Answers (1)

Seelenvirtuose
Seelenvirtuose

Reputation: 20608

You are using the float datatype.

This datatype is not able to precisely hold the value 0.525. See this code for making it clear:

float value = (float) (0.5 * 1.05);
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));

This prints out:

0.5249999761581421

Rounding such a value with the mode RoundingMode.HALF_UP will correctly yield 0.52.

The double value seems to be able to precisely store the value 0.525:

double value = 0.5 * 1.05;
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));

This will print the expected value:

0.525

Rounding that value with the mode RoundingMode.HALF_UP will now yield 0.53!

Caution: Even the double datatype does not store the value precisely!

Look at @MarkDickinson's comment. The stored value is 0.52500000000000002220446049250313080847263336181640625 which happens to be larger than 0.525 and only rounds by accident to the expected value.

So what to do?

The data types float and double are binary-based, whereas we humans tend to think decimal-based when dealing with numbers. Read the article "What Every Computer Scientist Should Know About Floating-Point Arithmetic" for much more information.

The solution is to use a decimal-based data type, which exists in BigDecimal.

Upvotes: 9

Related Questions