我想存储一个Point3D
对象的std::set
,我的比较函数定义如下(字典顺序):
bool operator<(const Point3D &Pt1, const Point3D &Pt2)
{
const double tol = 1e-5;
if(fabs(Pt1.x() - Pt2.x()) > tol)
{
return Pt1.x() < Pt2.x();
}
else if(fabs(Pt1.y() - Pt2.y()) > tol)
{
return Pt1.y() < Pt2.y();
}
else if(fabs(Pt1.z() - Pt2.z()) > tol)
{
return Pt1.z() < Pt2.z();
}
else
{
return false;
}
}
在某些情况下,set
包含相同的点,我认为问题来自比较功能,但我没有找到确切的问题。任何帮助将不胜感激!
您的公差概念没有正确建立 strict weak ordering ,因为它不是传递性的。举个例子,假设公差是1
.现在考虑:
a = 1
b = 2
c = 3
此处:!(a<b)
和 !(b<c)
,但是a<c
.这明显违反了严格弱排序的传递性要求。
如果你想实现一个有公差的比较,但它也是一个严格的弱排序,你必须以一致的方式对每个值进行舍入(例如,1.5 => 2
、0.75 => 1
、2.3 => 2
等)然后比较四舍五入的值。
这样做似乎毫无意义,因为double
我们已经这样做了,但精度最高。当你发现 1.4999999... != 1.5
时,你仍然会得到奇怪的行为。 .
你应该像下面这样写你的比较器,并放弃公差概念:
bool operator<(const Point3D &Pt1, const Point3D &Pt2)
{
//This can be replaced with a member/free function if it is used elsewhere
auto as_tie = [](Point3D const &Pt) {
//assumes the member functions return references
//to the internal `Point3D` values.
return std::tie(Pt.x(), Pt.y(), Pt.z());
};
return as_tie(Pt1) < as_tie(Pt2);
}
如果您绝对必须有容差,请在将值放入 Point3D
后立即对其进行舍入,或在比较前四舍五入值(取决于系统中的其他要求)。