简体   繁体   English

为什么我的比较运算符没有比较我的点长和双精度值?

[英]Why my compare operator is not comparing my point length and double value?

I create new operator to compare my point vector length and double value.我创建了新的运算符来比较我的点向量长度和双精度值。 I have condition to tolerate different which is less than 0.01.我有条件容忍小于 0.01 的差异。 When i using this operator to compare my Point and my double value (both values after approaching are same) but the operator == is not returning true.当我使用此运算符比较我的点和我的双精度值(接近后的两个值相同)但运算符 == 未返回 true 时。

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

This issue can be reproduced on gcc with 32 bit Intel architecture, without optimization.此问题可在 32 位 Intel 架构的 gcc 上重现,无需优化。 Here is an example of it happening: compiler explorer example .这是它发生的一个例子:编译器资源管理器示例

This is due to the infamous 323 bug of gcc, which struggles to work with Intel's 80 bit floating point registers, which are wider than the 64 bits of type double .这是由于 gcc 的臭名昭著的323 错误,它难以与英特尔的 80 位浮点寄存器一起工作,它比 64 位类型的double更宽。 Some of the values end up in the 80-bit register, and some values in the 64-bit memory value.一些值最终在 80 位寄存器中,一些值在 64 位 memory 值中。

In your case, approach(d) is called first, and then get spilled to memory when v.getLength() is called.在您的情况下,首先调用approach(d) ,然后在v.getLength()时溢出到 memory。 The value of approach(v.getLength()) , on the other hand, is not getting spilled and gets all of register's 80-bit precision.另一方面, approach(v.getLength())的值不会溢出并获得寄存器的所有 80 位精度。

When you compare an 80-bit accurate value, and a truncated 64-bit value, the comparison result is false .当您比较 80 位准确值和截断的 64 位值时,比较结果为false

A possible solution is to avoid the division by 100 in approach() , since it is what introduces the extra bits.一个可能的解决方案是避免在approach()中除以 100,因为它是引入额外位的原因。 Instead, you can try:相反,您可以尝试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM