c++ comparison of two double values not working pr

2019-01-07 23:09发布

问题:

This question already has an answer here:

  • How dangerous is it to compare floating point values? 9 answers

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 of 3.14 in the V() 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?

回答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;
}


回答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.