为什么我的比较运算符不比较我的点长度和双精度值?
Why my compare operator is not comparing my point length and double value?
我创建了新的运算符来比较我的点向量长度和双精度值。我有条件容忍小于 0.01 的差异。
当我使用此运算符比较我的 Point 和我的双精度值时(接近后的两个值相同)但运算符 == 未返回 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 上重现,无需优化。
这是它发生的一个例子:
compiler explorer example.
这是由于臭名昭著的 323 bug gcc,它很难与 Intel 的 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));
}
我创建了新的运算符来比较我的点向量长度和双精度值。我有条件容忍小于 0.01 的差异。 当我使用此运算符比较我的 Point 和我的双精度值时(接近后的两个值相同)但运算符 == 未返回 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 上重现,无需优化。 这是它发生的一个例子: compiler explorer example.
这是由于臭名昭著的 323 bug gcc,它很难与 Intel 的 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));
}