具有个人比较功能的 std::set 具有相同的值[重复]

Posted

技术标签:

【中文标题】具有个人比较功能的 std::set 具有相同的值[重复]【英文标题】:std::set with personal comparison function have identical values [duplicate] 【发布时间】:2014-06-09 10:35:52 【问题描述】:

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

【问题讨论】:

你的比较运算符需要实现严格的弱排序:***.com/questions/979759/… 那么问题来了:如何使用double 和容差实现严格的弱排序? 那么您的代码目前仅单独测试每个 x,y,z 坐标,您需要测试是否所有坐标都小于 epsilon,然后返回 false @EdChum 但如果所有三个差值都小于 epsilon,则运算符返回 false。 这些似乎是空间中的点。您是否考虑过使用欧几里得距离进行排序?容差会更容易实现。 【参考方案1】:

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

a = 1
b = 2
c = 3

这里:!(a&lt;b)!(b&lt;c),但 a&lt;c。这明显违反了严格弱排序的传递性要求。

如果你想实现一个有容差的比较,但它也是一个严格的弱排序,你必须以一致的方式对每个值进行四舍五入(例如,1.5 =&gt; 20.75 =&gt; 12.3 =&gt; 2 等)然后比较四舍五入的值。

这样做似乎毫无意义,因为doubles 已经这样做了,但要尽可能精确。当你发现 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 后立即四舍五入,或在比较之前立即对值进行四舍五入(取决于系统中的其他要求)。

【讨论】:

在我的情况下,我需要在比较之前使用容差和舍入值:static_cast&lt;int&gt;(xDouble*std::pow(10,nbDecimal)+0.5) 用于每个坐标。

以上是关于具有个人比较功能的 std::set 具有相同的值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能有两个具有相同功能的 goroutine 来查看彼此的值?

如何比较两列之间的值是不是具有相同的数字〜熊猫

比较 2 个表中的值并生成具有差异的新表

将一个表中的值与另一表中具有相同属性的值的平均值计算进行比较

找到重复的值并比较另一个键

c#如何检查SelectedListItem的两个列表是不是具有相同的值