Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe when compare 2 float/double directly in Java?

Tags:

java

android

Is it safe if I use comparision like this (a is int, b and c is float/double):

a == b
b == c

It may hear ridiculous, but in my old programing language, sometimes 1 + 2 == 3 is false (because left side returns 2.99999999999...). And, what about this:

Math.sqrt(b) == Math.sqrt(c)
b / 3 == 10 / 3 //In case b = 10, does it return true?
like image 906
Luke Vo Avatar asked Jul 22 '11 06:07

Luke Vo


2 Answers

In general, no it is not safe due to the fact that so many decimal numbers cannot be precisely represented as float or double values. The often stated solution is test if the difference between the numbers is less than some "small" value (often denoted by a greek 'epsilon' character in the maths literature).

However - you need to be a bit careful how you do the test. For instance, if you write:

if (Math.abs(a - b) < 0.000001) {
    System.err.println("equal");
}

where a and b are supposed to be "the same", you are testing the absolute error. If you do this, you can get into trouble if a and b are (say_ 1,999,999.99 and 2,000,000.00 respectively. The difference between these two numbers is less than the smallest representable value at that scale for a float, and yet it is much bigger than our chosen epsilon.

Arguably, a better approach is to use the relative error; e.g. coded (defensively) as

if (a == b ||
    Math.abs(a - b) / Math.max(Math.abs(a), Math.abs(b)) < 0.000001) {
    System.err.println("close enough to be equal");
}

But even this is not the complete answer, because it does not take account of the way that certain calculations cause the errors to build up to unmanageable proportions. Take a look at this Wikipedia link for more details.

The bottom line is that dealing with errors in floating point calculations is a lot more difficult than it appears at first glance.


The other point to note is (as others have explained) integer arithmetic behaves very differently to floating point arithmetic in a couple of respects:

  • integer division will truncate if the result is not integral
  • integer addition subtraction and multiplication will overflow.

Both of these happen without any warning, either at compile time or at runtime.

like image 138
Stephen C Avatar answered Sep 30 '22 22:09

Stephen C


You do need to exercise some care.

1.0 + 2.0 == 3.0

is true because integers are exactly representable.

Math.sqrt(b) == Math.sqrt(c) 

if b == c.

b / 3.0 == 10.0 / 3.0

if b == 10.0 which is what I think you meant.

The last two examples compare two different instances of the same calculation. When you have different calculations with non representable numbers then exact equality testing fails.

If you are testing the results of a calculation that is subject to floating point approximation then equality testing should be done up to a tolerance.

Do you have any specific real world examples? I think you will find that it is rare to want to test equality with floating point.

like image 24
David Heffernan Avatar answered Sep 30 '22 23:09

David Heffernan