Non-exact Math in Java

Well as far as I am concerned the Java primitives “float” and “double” should be removed from the Java language due to mis-use. Seems like a fairly harsh statement but let me explain.

Some background

Both in C/C++ and Java there exists a float/double numeric. The underlying mechanism (I won’t go into that here) that stores this value can only approximate some values. For example the number “1.01” is approximated by the number “1.0100000000000000088817841970012523233890533447265625”. If you perform some math on these approximated numbers you can quickly get some unexpected results.

A Simple program to demonstrate

Here is a simple program to demonstrate the use of doubles in arithmetic. The first part constructs a BigDecimal with a double. We see that using the double we get an approximated number. If we use the String constructor our number is exact.

The second half of the program takes “0.01” and adds it to “1.00” 100 times. This should equal “2.0” but of course doesn’t.

public static void main(String[] args) {
    //BigDecimals constructed with doubles
    System.out.println("BigDecimal(\"1.01\") = "+new BigDecimal("1.01"));
    System.out.println("BigDecimal(1.01) = "+new BigDecimal(1.01));

    //Add 0.01 100 times to 1.00
    double d = 1.00;
    double total = (d  + (100 * 0.01));
    for (int i = 0; i < 100; i++) {
        d+=0.01;
    }
    System.out.println("1.00 + (100 * 0.01) = "+total);
    System.out.println("1.00 + .01 (100 times in a loop) = " + d);
}

When you run this code you get the following output:

BigDecimal("1.01") = 1.01
BigDecimal(1.01) = 1.0100000000000000088817841970012523233890533447265625
1.00 + (100 * 0.01) = 2.0
1.00 + .01 (100 times in a loop) = 2.000000000000001

Avoid the potential problem

Every project I am on I insist that no doubles or floats are used. Always use BigDecimals but never use the BigDecimal with the double constructor. A project I am working on now uses BigDecimals with double constructors in some test code. This actually caused me some grief when the values were persisted to the database.

I remember back many moons ago working on a financial loan application that calculated interest and payment information. Over the span of a 10 year loan you would be out several dollars if you used doubles to calculate it. BigDecimals allowed us to calculate it perfectly.

I just believe the best thing to do is simply try and avoid the problem. Maybe a future version of Java will change the implementation of double to be consistent with BigDecimal.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply