具有个人比较功能的std :: set具有相同的值

时间:2014-06-09 10:35:52

标签: c++ stdset

我想存储一个std::set Point3D个对象,我的比较函数定义如下(词典顺序):

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 个答案:

答案 0 :(得分:7)

您的容忍概念未正确建立strict weak ordering,因为它不具有传递性。为了举例,假设容差是1。现在考虑:

a = 1
b = 2
c = 3

此处:!(a<b)!(b<c),但a<c。这明显违反了严格弱序的传递要求。

如果要实现具有容差的比较,但也是严格的弱排序,则必须以一致的方式舍入每个值(例如1.5 => 20.75 => 1,{{ 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); } 后立即对值进行舍入,或者在比较前立即舍入值(取决于其他要求)你的系统)。