我写了一个测试用例:
//environment: compiler=msvc140-x64 system=win10
#include <map>
#include <iostream>
int main(int argc, char* argv[])
{
std::map<double, std::string> mapd2str;
double dval1 = 1;
mapd2str[dval1] = std::to_string(dval1);
double dval2 = 1 + 1e-6;
mapd2str[dval2] = std::to_string(dval2);
for (auto& p : mapd2str)
{
std::cout << "first=" << p.first << ", second=" << p.second << std::endl;
}
return 0;
}
输出如下:
first=1, second=1.000000
first=1.00001, second=1.000010
我将dval2更改为
1 + 10e-20
后,输出如下:
first=1, second=1.000000
那么,如果我使用double或者float作为std::map的key,会有什么风险吗?
风险在于双打的本质以及你如何使用它。您看到 1 + 10e-20 变成 1 的原因是因为它达到了双精度的极限并环绕。
想象一下,你只能数个位数,从 0 开始。然后递增到 1、2、3...最终达到 9。如果再次递增,它会回到 0,因为我们无法存储10 仅使用个位数,并且进位被简单地丢弃。这基本上就是这里发生的事情。
可以通过确保双精度型密钥永远不会超过双精度型的数值限制来管理该风险。或者您可以使用更大尺寸的数据类型(因此能够表示更大范围的值)。