Search code examples
javaroundingbigdecimal

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);

Solution

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