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 conditions. Java programmers often make the mistake of using floating-point numbers in a loop and checking conditions with the == operator, in the worst case this could create an infinite loop, causing your Java application to hung.

For example, the 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 the balance until the 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 to 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, have suggested avoiding using double and float for monetary calculation in his book Java Puzzlers.

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 the 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 like 1/3 cannot be represented exactly using float and double in Java.

How to compare float and double values in Java.



After running the 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.


Some tips while using float and double in Java

Do all calculations 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 the mistake of comparing floating points number with == operator is that for some fractions, it does work properly like 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 conditions involving float and double values then 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 an expert of floating-point numbers, know about precision, and have a very good understanding of floating-point arithmetic in Java.

17 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
    Replies
    1. Hello @Andrew, yes, that's also an option, thanks for suggestion.

      Delete
  4. The solution for the problem can be achieved with the below code, without using BigDecimal.
    for (Double balance = 0d; balance<=10; balance += 0.1) {
    System.out.println(balance.floatValue());
    }

    ReplyDelete
    Replies
    1. Hello Varun, Agree, one should always use <= to compare floating point values in loop.

      Delete
  5. package hid;
    import java.util.*;


    public class shyam {


    public static void main(String args[]){
    String s1="shyam is an intelligent boy ";
    String [] s2=s1.split(" ");
    for(String x : s2)
    {
    System.out.print(x+" ");
    }

    int len=s2.length;
    System.out.print(len+" ");

    for(int i=len-1;i>=0;i--)
    {
    System.out.print(s2[i]+" ");
    }

    }
    }

    ReplyDelete
    Replies
    1. Sorry Shyam, but how is this related to the topic?

      Delete
  6. Hi, I need to check if the double variable is empty in a if condition. I tried the following but nothing worked. please help asap! Thanks in advance!

    Methods I've used but didnt work:

    double num = 0 or just think this is empty because this will be taken from user input

    1. num.isNaN
    2. num == null
    3. Turned num value to string and check if its empty


    ReplyDelete
    Replies
    1. Hello Uditha, the default value of double is 0.0 but that is not a good criteria. I suggest you to use Double, the wrapper class instead of double primitive value in this case. If user doesn't set then Double will be null something like this

      Double userInput = Scanner.nextDouble();

      if(userInput == null){

      }

      Delete
  7. you can use '!= 10f' depending on the circumstances. I was stuck on this for like 10 mins cause of this

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.