set::find 和 std::find 都无法在一个集合中找到一些双元素

Both set::find and std::find fail to find only some double elements in a set

本文关键字:find 集合 一个 元素 std set      更新时间:2023-10-16

我正在开发一个大代码库,并希望使用 STL 中的 set-s 来存储双元素。我刚刚进行了一些测试,发现了一些非常奇怪的东西。

这是我的源代码

#include <iostream>
#include <set>
#include <numeric>
#include <algorithm>
int main()
{
    double iter = 0.001;
    int count = 0;
    std::set<double> S;
    while(count < 10) 
    {
        S.insert(iter);
        std::cout << "Inserted element is " << iter << std::endl;
        iter += 0.001;
        count++;
    }
    for (std::set<double>::iterator i = S.begin(); i != S.end(); i++) 
    {
       double element = *i;
       std::cout << "The element in the set is " << element << std::endl;
    }
    std::cout << "The count of the element to be found is " << S.count(0.009) << std::endl;
    if (S.find(0.008) != S.end())
        std::cout << "set::find found it!" << std::endl;
    else 
        std::cout << "set::find didn't find it!" << std::endl;  
    if (std::find(S.begin(), S.end(), 0.009) != S.end())
        std::cout << "std::find found it!" << std::endl;
    else
        std::cout << "std::find didn't find it!" << std::endl;
    return 0;
}

现在,奇怪的是,set::findstd::find都能够找到所有元素,直到0.008,但在那之后找不到任何东西。

我为上述代码获得的输出如下所示:

Inserted element is 0.001
Inserted element is 0.002
Inserted element is 0.003
Inserted element is 0.004
Inserted element is 0.005
Inserted element is 0.006
Inserted element is 0.007
Inserted element is 0.008
Inserted element is 0.009
Inserted element is 0.01
The element in the set is 0.001
The element in the set is 0.002
The element in the set is 0.003
The element in the set is 0.004
The element in the set is 0.005
The element in the set is 0.006
The element in the set is 0.007
The element in the set is 0.008
The element in the set is 0.009
The element in the set is 0.01
The count of the element to be found is 0
set::find found it!
std::find didn't find it!

请注意,我要求set::find查找0.008,而我要求countstd::find分别计数和查找0.009。我只是想知道为什么我会看到这样的异常。

还值得一提的是,这两个find函数在查找整数元素时绝对没有问题。我想知道这是否是一个double问题。即使是这样,我也不确定为什么它能够找到一些元素而不是全部。

我不确定是什么原因导致此错误,但如果它有任何用处,我会在带有 gcc 10.10.3 的 Mac OS X 4.9.2 上工作。

> 是的,这是一个double"问题" - 当您连续将0.001添加到iter时,舍入误差可能会累积,以至于结果值与您预期的不匹配(例如,您的硬编码0.008)。

由于set已排序,因此您可能希望使用例如 lower_bound查找附近的元素,然后使用一些差异容差进行检查。 例如,检查找到的值和期望值之间的绝对差值是否小于 epsilon 量。 S.O.上有数百个关于如何准确实施比较的问题......例如这里。

set中使用浮点数的另一个具体问题是,当您期望它们时,您可能不会insert被视为重复项,或者另一方面,insert可能会拒绝插入两个您不希望是重复的值,因为它们生成过程中的舍入误差使它们相同。 在给定完全准确的计算的情况下,两个极其相似的值的顺序也可能与您在数学上期望的顺序相反。