我们知道NaN!= IEEE的NaN浮点数。结果,浮点数上的许多“显而易见”操作都有一个隐藏的陷阱,其中数据中的NaN可能会把事情弄得一团糟。例如:
显而易见的方法是这样的:
template <typename T>
struct NaNSafeEqual0 {
bool operator()(const T& a, const T& b) const {
if (!(a == a) || !(b == b)) {
return (a == a) == (b == b); // <- Still has a gotcha: see below.
}
return a == b; // This deals with 0.0 == -0.0;
}
};
由于std::hash<float>
散列按位值(至少在某些实现中)的事实使情况变得复杂,因此对于std::unordered_set<float, std::hash<float>, ...>
,我们需要KeyEqual
函数来比较KeyEqual()(NaN, NaN) == true
但KeyEqual()(NaN, -NaN) == false
。对于std::unordered_set
,我们可以进行按位比较,除了我们仍然需要-0 == 0
。
我敢肯定我可以写出健壮的(也许不是很快?)NaNSafeLess<T>
和NaNSafeEqual<T>
,但是这种事情众所周知很难正确地完成,此外,使它通用。我认为这对于内置POD类型可能是正确的,尽管它不是完全通用的,因为它会在static_assert
时sizeof(T) > sizeof(std::size_t)
,并且会以{cy}的方式使用union
。>
template <typename T>
struct NaNSafeEqual {
std::size_t operator()(const T& a, const T& b) const {
if (a == a || b == b) {
return a == b; // At least one isn't nan.
}
static_assert(sizeof(T) <= sizeof(std::size_t));
union {
T data;
std::size_t s;
} ua, ub;
ua.s = 0;
ub.s = 0;
ua.data = a;
ub.data = b;
return ua.s == ub.s;
}
};
因此:是否存在写less
和equal
的通用标准方法,以允许在std :: set和/或std :: unordered_set中安全存储浮点数?如果没有,Boost或其他广泛使用的库是否提供一个?