>我创建了一个新的运算符来比较我的点向量长度和双精度值。我有条件容忍小于0.01的不同。 当我使用此运算符比较我的点和我的双精度值(接近后的两个值相同(但运算符 == 没有返回 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;
}
此问题可以在具有 32 位 Intel 架构的 gcc 上重现,无需优化。 下面是它发生的一个例子: 编译器资源管理器示例。
这是由于臭名昭著的 gcc 323 错误,它难以与英特尔的 80 位浮点寄存器配合使用,后者比double
型 64 位更宽。一些值最终出现在 80 位寄存器中,而一些值最终出现在 64 位内存值中。
在您的情况下,首先调用approach(d)
,然后在调用v.getLength()
时溢出到内存中。另一方面,approach(v.getLength())
的值不会被溢出,并获得寄存器的所有80位精度。
比较 80 位准确值和截断的 64 位值时,比较结果为false
。
一个可能的解决方案是避免在approach()
中除以 100 ,因为它会引入额外的位。相反,您可以尝试:
static constexpr double magnitude = 100.0;
const bool operator== (double d, const Point &v){
return floor(d * magnitude) == floor(v.getLength() * magnitude));
}