comparing float/double values using == operator

The code review tool I use complains with the below when I start comparing two float values using equality operator. What is the correct way and how to do it? Is there a helper function (commons-*) out there which I can reuse?

Description

Cannot compare floating-point values using the equals (==) operator

Explanation

Comparing floating-point values by using either the equality (==) or inequality (!=) operators is not always accurate because of rounding errors.

Recommendation

Compare the two float values to see if they are close in value.

float a;
float b;

if(a==b)
{
..
}

Solution 1:

IBM has a recommendation for comparing two floats, using division rather than subtraction - this makes it easier to select an epsilon that works for all ranges of input.

if (abs(a/b - 1) < epsilon)

As for the value of epsilon, I would use 5.96e-08 as given in this Wikipedia table, or perhaps 2x that value.

Solution 2:

It wants you to compare them to within the amount of accuracy you need. For example if you require that the first 4 decimal digits of your floats are equal, then you would use:

if(-0.00001 <= a-b && a-b <= 0.00001)
{
..
}

Or:

if(Math.abs(a-b) < 0.00001){ ... }

Where you add the desired precision to the difference of the two numbers and compare it to twice the desired precision.

Whatever you think is more readable. I prefer the first one myself as it clearly shows the precision you are allowing on both sides.

a = 5.43421 and b = 5.434205 will pass the comparison

Solution 3:

private static final float EPSILON = <very small positive number>;

if (Math.abs(a-b) < EPSILON)
   ...

As floating point offers you variable but uncontrollable precision (that is, you can't set the precision other than when you choose between using double and float), you have to pick your own fixed precision for comparisons.

Note that this isn't a true equivalence operator any more, as it isn't transitive. You can easily get a equals b and b equals c but a not equals c.

Edit: also note that if a is negative and b is a very large positive number, the subtraction can overflow and the result will be negative infinity, but the test will still work, as the absolute value of negative infinity is positive infinity, which will be bigger than EPSILON.

Solution 4:

Use commons-lang

org.apache.commons.lang.math.NumberUtils#compare

Also commons-math (in your situation more appropriate solution):

http://commons.apache.org/math/apidocs/org/apache/commons/math/util/MathUtils.html#equals(double, double)