Why you shouldn't use == with float and double in Java?

In this article, you are going to learn why you shouldn't use == with float and double in Java? Especially for checking loop termination condition. Java programmers often make the mistake of using floating point number in a loop and checking condition with the == operator, in the worst case this could create an infinite loop, causing your Java application to hung.


For example, following code will not work as you expect :

for(double balance = 10; balance!=0; balance-=0.1) {
   System.out.println(balance);
}

You would think that this code will print balance until balance reduced to zero. Since we are doing balance = balance - 0.1, you  would expect it to print something like 10, 9.9, 9.8 and so on until it reaches zero. But for your surprise, this will cause an infinite loop in Java, it will never end, Why? because 0.1 is an infinite binary decimal, the balance will never be exactly 0.

This is the reason many programmers, including Joshua Bloch, has suggest to avoid using double and float for monetary calculation in his book Java Puzzlers.

how to compare float and double in Java


Now, this brings a more pertinent question, how do you compare floating point numbers in Java? if == is not going to work then how can I write a similar loop, because that's a very general case and it would be unfortunate if you can't test for decimal points? Let's find out the right way to compare floating point values in Java in next section.


How to compare float and double values in Java?

As we have seen in the first paragraph that use of == operator can cause an endless loop in Java, but is there a way to prevent that loop from running infinitely? Yes, instead of using equality operator (==), you can use relational operator e.g. less than (<) or greater than (>) to compare float and double values.


By changing the above code as following, you can prevent the loop from infinitely  :

for(double balance = 10; balance > 0; balance-=0.1) {
   System.out.println(balance);
}

If you think a little bit then you will realize that greater than will definitely end this loop, but don't expect it to print numbers like 9.9, 9.8, 9.7 because floating point numbers are a just approximation, they are not exact. Some numbers e.g. 1/3 cannot be represented exactly using float and double in Java.

After running following program on your computer you may end up with something like this

/**
 * Don't use == operator with float and double values in Java
 *
 * @author Javin Paul
 */
public class FloatInForLoop {
    public static void main(String args[]) {
        for (double balance = 10; balance > 0; balance -= 0.1) {
            System.out.println(balance);
        }
    }
}
Output:
10.0
9.9
9.8
9.700000000000001
9.600000000000001
9.500000000000002
9.400000000000002
9.300000000000002
...
....
0.9000000000000187
0.8000000000000187
0.7000000000000187
0.6000000000000187
0.5000000000000188
0.4000000000000188
0.3000000000000188
0.2000000000000188
0.1000000000000188
1.8790524691780774E-14

You can see that result is nowhere close to our expectation, and that's why float and double are not recommended for financial calculation or where the exact result is expected.

How to compare float and double values in Java.


Some tips while using float and double in Java

Do all calculation in float/double but for comparison, always compare approximation instead of precise values e.g. instead of checking for 10.00 check for > 9.95 as shown below

if (amount == 100.00) // Not Ok
if (amount > 99.995)  // Ok

One reason, why many programmers make mistake of comparing floating points number with == operator is that, for some fraction it does work properly e.g. if we change 0.1 to 0.5 the loop in question will work properly as shown below :

for (double balance = 10; balance > 0; balance -= .5) {
   System.out.println(balance);
}

Output :
10.0
9.5
9.0
8.5
8.0
7.5
7.0
6.5
6.0
5.5
5.0
4.5
4.0
3.5
3.0
2.5
2.0
1.5
1.0
0.5

Alternatively, you can use BigDecimal for exact calculation.  You can also try rewriting the same code using BigDecimal class instead of double primitive.

That's all about why you shouldn't use == operator with float and double in Java. If you have to check condition involving float and double values than instead of using == always use relational operator e.g. < or > for comparing floating point numbers in Java. I repeat, don't use double and float for monetary calculation unless you are expert of floating point numbers, knows about precision and have very good understanding of floating point arithmetic in Java.

Further Reading
Try to solve Java Puzzle on double and float calculation from Java Puzzlers book.


8 comments:

  1. I think its just to demonstrate and be on safer side. >=10/0 will also prevent infinite loop.

    ReplyDelete
    Replies
    1. I mean >=10.00 will also prevent loop running infinitely.

      Delete
    2. It's also safer. What if the value lands on 9.9999967347?

      You also need to be careful about where the variable ends up. while(i>0)--i; is guaranteed to end up at zero, whereas while(d>0)d-=0.1; isn't.

      Delete
  2. Why does the loop work with balance 0.5?

    ReplyDelete
    Replies
    1. because 0.5 can be represented exactly using float and double but 0.1 cannot.

      Delete
  3. Best way is
    https://docs.oracle.com/javase/7/docs/api/java/lang/Float.html#compare(float,%20float)

    ReplyDelete