是否有通用的标准方法将浮点数存储在std :: set和/或std :: unordered_set中?

时间:2019-04-23 14:01:11

标签: c++ stl floating-point nan

我们知道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) == trueKeyEqual()(NaN, -NaN) == false。对于std::unordered_set,我们可以进行按位比较,除了我们仍然需要-0 == 0

我敢肯定我可以写出健壮的(也许不是很快?)NaNSafeLess<T>NaNSafeEqual<T>,但是这种事情众所周知很难正确地完成,此外,使它通用。我认为这对于内置POD类型可能是正确的,尽管它不是完全通用的,因为它会在static_assertsizeof(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;
    }
};

因此:是否存在写lessequal的通用标准方法,以允许在std :: set和/或std :: unordered_set中安全存储浮点数?如果没有,Boost或其他广泛使用的库是否提供一个?

0 个答案:

没有答案