Почему мой оператор сравнения не сравнивает мою длину точки и двойное значение? - PullRequest
0 голосов
/ 27 мая 2020

Я создаю новый оператор для сравнения длины вектора точки и двойного значения. У меня есть условия терпеть другое, которое меньше 0,01. Когда я использую этот оператор для сравнения моей точки и моего двойного значения (оба значения после приближения одинаковы), но оператор == не возвращает истину.

class Point {
private:
    double x, y, z;
public:
    Point() { x = y = z = 0.0; }
    Point(double v) { x = y = z = v; }
    Point(double x, double y, double z){
        this->x = x; this->y = y; this->z = z;
    }
    double getLength(){
        return sqrt(pow(x,2)+pow(y,2)+pow(z,2));
    }
    friend const bool operator== (double &d, Point &v);
};

double approach(double num){
    return floor(num*100)/100;
}

const bool operator== (const double &d, Point &v){
    return (approach(d) == approach(v.getLength()));
}

int main()
{
    Point p1(3,4,1);
    cout << p1.getLength() << endl; // 5.09902
    cout << approach(p1.getLength()) << endl;
    cout << approach(5.091) << endl;
    if(5.091 == p1)
        cout << "True";
    return 0;
}

1 Ответ

0 голосов
/ 27 мая 2020

Эта проблема может быть воспроизведена на g cc с 32-битной архитектурой Intel без оптимизации. Вот пример того, как это происходит: пример проводника компилятора .

Это связано с печально известной ошибкой 323 в g cc, которая изо всех сил пытается работать с Intel 80-битные регистры с плавающей запятой, которые шире, чем 64-битные регистры типа double. Некоторые значения попадают в 80-битный регистр, а некоторые - в 64-битное значение памяти.

В вашем случае сначала вызывается approach(d), а затем переливается в память при вызове v.getLength(). С другой стороны, значение approach(v.getLength()) не теряется и получает всю 80-битную точность регистра.

Когда вы сравниваете 80-битное точное значение и усеченное 64-битное значение, результат сравнения будет false.

Возможное решение - избежать деления на 100 в approach(), поскольку он вводит дополнительные биты. Вместо этого вы можете попробовать:

static constexpr double magnitude = 100.0;
const bool operator== (double d, const Point &v){
    return floor(d * magnitude) == floor(v.getLength() * magnitude));
}
...