I've writed a test case:
//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;
}
the output is as follow:
first=1, second=1.000000
first=1.00001, second=1.000010
after I changed the dval2 to 1 + 10e-20, the output is as follow:
first=1, second=1.000000
so, if I use the double or float as the key of std::map, is there any risk?
It depends on what you refer to as "risk". The
std::mapis totally fine withfloatordoubleas keys.A risk might be that keys you expect to be identical are not and that keys you expect to be different are in fact identical.
1 + 10e-20is the samedoubleas1.0becausedoublehas finite precision. There are other cases where intuition fails. See Is floating point math broken? for more details. Though, I repeat, the map has no issue with floating numbers as keys. If you insert a value for key0.123and later search for the value with key0.123you will find the right value. There is no risk in that.If you do write a custom comparator, make sure it implements a strict weak ordering. The usual epsilon comparison of floating point numbers cannot do that! Also
infandnanrequire to take care when implementing the comparator.