Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing floating point number to zero

The C++ FAQ lite "[29.17] Why doesn't my floating-point comparison work?" recommends this equality test:

#include <cmath>  /* for std::abs(double) */  inline bool isEqual(double x, double y) {   const double epsilon = /* some small number such as 1e-5 */;   return std::abs(x - y) <= epsilon * std::abs(x);   // see Knuth section 4.2.2 pages 217-218 } 
  1. Is it correct, that this implies that the only numbers which are equal to zero are +0 and -0?
  2. Should one use this function also when testing for zero or rather a test like |x| < epsilon?

Update

As pointed out by Daniel Daranas the function should probably better be called isNearlyEqual (which is the case I care about).

Someone pointed out "Comparing Floating Point Numbers", which I want to share more prominently.

like image 232
Micha Wiedenmann Avatar asked Nov 07 '13 13:11

Micha Wiedenmann


People also ask

What is a better way to compare floating point values?

To compare two floating point or double values, we have to consider the precision in to the comparison. For example, if two numbers are 3.1428 and 3.1415, then they are same up to the precision 0.01, but after that, like 0.001 they are not same.

Why do we never use == to compare floating point numbers?

Because floating point arithmetic is different from real number arithmetic. Bottom line: Never use == to compare two floating point numbers. Here's a simple example: double x = 1.0 / 10.0; double y = x * 10.0; if (y !=

Can you compare floats and integers?

As to the first question about whether the comparison is valid, the answer is yes. It is perfectly valid. If you want to know if a floating point value is exactly equal to 3, then the comparison to an integer is fine. The integer is implicitly converted to a floating point value for the comparison.


1 Answers

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".

like image 198
Ben Voigt Avatar answered Oct 06 '22 16:10

Ben Voigt