Comparing floating point number to zero
You are correct with your observation.
If x == 0.0
, then abs(x) * epsilon
is zero and you're testing whether abs(y) <= 0.0
.
If y == 0.0
then you're testing abs(x) <= abs(x) * epsilon
which means either epsilon >= 1
(it isn't) or x == 0.0
.
So either is_equal(val, 0.0)
or is_equal(0.0, val)
would be pointless, and you could just say val == 0.0
. If you want to only accept exactly +0.0
and -0.0
.
The FAQ's recommendation in this case is of limited utility. There is no "one size fits all" floating-point comparison. You have to think about the semantics of your variables, the acceptable range of values, and the magnitude of error introduced by your computations. Even the FAQ mentions a caveat, saying this function is not usually a problem "when the magnitudes of x and y are significantly larger than epsilon, but your mileage may vary".
No.
Equality is equality.
The function you wrote will not test two doubles for equality, as its name promises. It will only test if two doubles are "close enough" to each other.
If you really want to test two doubles for equality, use this one:
inline bool isEqual(double x, double y)
{
return x == y;
}
Coding standards usually recommend against comparing two doubles for exact equality. But that is a different subject. If you actually want to compare two doubles for exact equality, x == y
is the code you want.
10.000000000000001 is not equal to 10.0, no matter what they tell you.
An example of using exact equality is when a particular value of a double is used as a synonym of some special state, such as "pending calulation" or "no data available". This is possible only if the actual numeric values after that pending calculation are only a subset of the possible values of a double. The most typical particular case is when that value is nonnegative, and you use -1.0 as an (exact) representation of a "pending calculation" or "no data available". You could represent that with a constant:
const double NO_DATA = -1.0;
double myData = getSomeDataWhichIsAlwaysNonNegative(someParameters);
if (myData != NO_DATA)
{
...
}
If you are only interested in +0.0
and -0.0
, you can use fpclassify
from <cmath>
. For instance:
if( FP_ZERO == fpclassify(x) ) do_something;