set::find 和 std::find 都无法找到集合中的某些双精度元素
Both set::find and std::find fail to find only some double elements in a set
我正在开发一个大型代码库,想使用 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::find
和 std::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
,而我要求 count
和 std::find
分别计算和找到 0.009
。我只是想知道为什么我会看到这样的异常现象。
还值得一提的是,find
函数在查找整数元素时完全没有问题。我想知道这是否是 double
问题。即使是这样,我不确定为什么它能够找到一些元素而不是全部。
我不确定是什么导致了这个错误,但如果它有任何用处,我在 Mac OS X 10.10.3 和 gcc 4.9.2 上工作。
是的,它是 double
"issue" - 当您连续将 0.001
添加到 iter
时,舍入误差可能会累积,使得结果值与您的值不匹配可能会期望(例如,您的硬编码 0.008
)。
因为 set
已排序,您可能需要使用例如lower_bound
to find a nearby element, then check using some tolerance for differences. For example, checking that the absolute difference between the found and expected values is less than an epsilon amount. There are hundreds of questions on S.O. about how exactly to implement the comparison... e.g. here.
在 set
中使用浮点数的另一个特定问题是,当您期望它们时,您可能不会将 insert
视为重复项,或者另一方面 insert
可能会拒绝插入两个您不希望重复的值,因为它们生成过程中的舍入误差使它们完全相同。与您在数学上期望的完全准确的计算相比,两个极其相似的值的顺序也有可能颠倒。
我正在开发一个大型代码库,想使用 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::find
和 std::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
,而我要求 count
和 std::find
分别计算和找到 0.009
。我只是想知道为什么我会看到这样的异常现象。
还值得一提的是,find
函数在查找整数元素时完全没有问题。我想知道这是否是 double
问题。即使是这样,我不确定为什么它能够找到一些元素而不是全部。
我不确定是什么导致了这个错误,但如果它有任何用处,我在 Mac OS X 10.10.3 和 gcc 4.9.2 上工作。
是的,它是 double
"issue" - 当您连续将 0.001
添加到 iter
时,舍入误差可能会累积,使得结果值与您的值不匹配可能会期望(例如,您的硬编码 0.008
)。
因为 set
已排序,您可能需要使用例如lower_bound
to find a nearby element, then check using some tolerance for differences. For example, checking that the absolute difference between the found and expected values is less than an epsilon amount. There are hundreds of questions on S.O. about how exactly to implement the comparison... e.g. here.
在 set
中使用浮点数的另一个特定问题是,当您期望它们时,您可能不会将 insert
视为重复项,或者另一方面 insert
可能会拒绝插入两个您不希望重复的值,因为它们生成过程中的舍入误差使它们完全相同。与您在数学上期望的完全准确的计算相比,两个极其相似的值的顺序也有可能颠倒。