c++ comparison of two double values not working properly
Solution 1
Comparing floating point values using the ==
operator is very error prone; two values that should be equal may not be due to arithmetic rounding errors. The common way to compare these is to use an epsilon:
bool double_equals(double a, double b, double epsilon = 0.001)
{
return std::abs(a - b) < epsilon;
}
Solution 2
There are two problems with floating point comparisons:
(1) Floating point operations usually involve at least tiny rounding errors which are hard to predict. Therefore two floating point operations that should mathematically give the same result (like 4.7 * (1.0 / 3.14) vs. 4.7 / 3.14) may give different results.
(2) The compiler is allowed to do floating point operations sometimes with higher precision than necessary. It is also allowed to do the exact same floating point operations with just the precision that was necessary at other times. Therefore the exact same operation may produce slightly different results, which is what you see here.
To solve the OP's problem, this looks like it is caused by (2). I'd try to find if there are any compiler options that can prevent the compiler from using higher precision than needed.
Related videos on Youtube
tuks
Updated on July 05, 2022Comments
-
tuks almost 2 years
Look at this code:
#include <cmath> #include <iostream> using namespace std; class Sphere { double r; public: double V() const { return (4/3) * 3.14 * pow(r,3); } bool equal(const Sphere& s) const { cout << V() << " == " << s.V() << " : " << ( V() == s.V() ); return ( V() == s.V() ); } explicit Sphere(double rr = 1): r(rr){} }; main() { Sphere s(3); s.equal(s); }
The output is
84.78 == 84.78 : 0
which means the same method doesn't return the same value every time, even though all parameters are static?But if I write
3.0
instead of3.14
in theV()
method definition, like this:double V() const { return (4/3) * 3.0 * pow(r,3); }
Then, the output is:
84.78 == 84.78 : 1
What is going on here? I need this method, for my program, which will compare volumes of two objects, but it is impossible? I banged my head for so long to figure out what is the cause of the problem and luckily I found it, but now I don't understand why?? Does it have something to do with the compiler (GCC) or am I missing something important here?
-
yngccc over 10 yearsyou simply don't test floating point number for equality like that.
-
Mike Seymour over 10 yearsUsually it's a bad idea to test floating point values for equality, since small rounding errors can give unexpected results. But, as you say, this does the same calculation twice with the same input, so the test should pass. It does with at least one version of GCC: ideone.com/FPjRVN. What version and platform are you using?
-
Mike Seymour over 10 years@tuks: Your professor might not have said anything, but another said rather a lot: cl.cam.ac.uk/teaching/1011/FPComp/floatingmath.pdf
-
tuks over 10 years@AdamBurry yeah I see... it's because of (4/3), it should be (4.0/3)
-
-
Adam Burry over 10 yearsSee for more detailed discussion: cygnus-software.com/papers/comparingfloats/…
-
Pete Becker over 10 yearsNo. "Almost equals" is an advanced technique; it should not be used by beginners. One serious problem that it has it that
a almost equals b
andb almost equals c
does not imply thata almost equals c
. -
nikolas over 10 years@PeteBecker Floating point arithmetics are not trivial, there is no "beginner's way" of doing this.
-
Pete Becker over 10 years@nijansen - true; but "almost equals" is almost always not the right solution.
-
gnasher729 almost 10 yearsI wouldn't expect double_equals (1e-6, -1e-5) to return "true".