Yes, use standard operator<
in a set or a map. Most fuzzy double
comparators are not strict enough to be used in a map
or set
. (And hope to hell that you aren't messing around with floating point modes while accessing said map...)
I would advise to use multimap
or multiset
, because two values you think are equal might be slightly different. If you are already expecting multiple entries, you should handle almost-equal entries much better.
Next, when searching for a hit do lower_bound(x - epsilon)
and upper_bound(x + epsilon)
in order to catch entries in the map that aren't where you think they are.
Ie, here is "is this double
in this multiset<double>
" code:
typedef std::multiset<double> double_set;
std::pair< double_set::iterator, double_set::iterator >
get_equal_range( double_set& s, double d, double epsilon = 0.00001 )
{
auto lower = s.lower_bound( d-epsilon );
auto upper = s.upper_bound( d+epsilon );
return std::make_pair( lower, upper );
}
std::pair< double_set::const_iterator, double_set::const_iterator >
get_equal_range( double_set const& s, double d, double epsilon = 0.00001 )
{
auto lower = s.lower_bound( d-epsilon );
auto upper = s.upper_bound( d+epsilon );
return std::make_pair( lower, upper );
}
bool TestMembership( double_set const& s, double d, double epsilon = 0.00001 )
{
auto range = get_equal_range( s, d, epsilon );
return range.first != range.second;
}
So a given double
could map to a range of entries, or have more than 1 hit in the set
.
Stolen from a great answer below: Default double operator<
will screw your map
or set
up if you pass NaN
in.
When putting things into map
and set
(and multi versions), you must maintain the strict weak ordering rules. If you fail, you will get seemingly random crashes, and the occasional infinite loop: the code in map
and set
is not robust against ordering failure.