与个人比较函数集合具有相同的值

std::set with personal comparison function have identical values

本文关键字:集合 比较 函数      更新时间:2023-10-16

我想存储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包含相同的点,我认为问题来自比较函数,但我没有找到确切的问题。任何帮助将不胜感激!

您的容差概念没有正确地建立严格的弱排序,因为它不是可传递的。为了方便示例,假设容忍度为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后立即将其四舍五入,或者在比较之前立即将值四舍五入(取决于系统中的其他要求)。