如果数组的第一个元素是 NAN,如何防止 std::min 和 max 到 return NAN?

How to prevent std::min and max to return NAN if the first element of the array is NAN?

有没有办法让 min/max (std::min_element) 忽略所有 NAN?我的意思是,它似乎忽略了中间的 NAN,但如果 第一个元素是 NAN.

样本:

template <typename T> inline void GetMinMax(const T* data, const int len, T& min, T& max)
{
    min = *std::min_element(data, data + len);
    max = *std::max_element(data, data + len);
}

float min, max;
std::array<float, 4> ar1 = { -12, NAN, NAN, 13 };
GetMinMax<float>(&ar1[0], ar1.size(), min, max); //min: -12. max: 13

std::array<float, 4> ar2 = { -12, 3, 13, NAN };
GetMinMax<float>(&ar2[0], ar2.size(), min, max);//min: -12. max: 13

std::array<float, 4> ar3 = { NAN, -12, 3, 13 };
GetMinMax<float>(&ar3[0], ar3.size(), min, max);//min: -nan(ind). max: -nan(ind)  !!!!

NAN 和其他数字比较起来很扭曲,见

所以您需要做的是提供自定义比较函数,以便 NAN 不是元素 std::min_element return。可能只是让“NAN < x”return 为假,让“x < NAN”return 为真。类似于 std::max_element 的“>”。或者尝试重载 <=>.

注意:解决方案可能取决于您的 STL 实现,具体取决于实现使用的比较运算符。

最安全的方法是在应用任何min-max标准算法之前删除范围内的所有NaN值。 =43=]

考虑 std::min_element1:

的可能实现
template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{
    if (first == last) return last;
 
    ForwardIt smallest = first;       // <-- If the first is a NaN...
    ++first;
    for (; first != last; ++first) {
        if (*first < *smallest) {     // <-- This condition will always be FALSE
            smallest = first;
        }
    }
    return smallest;                  // <-- An iterator to a NaN is returned
}

更正式地说,C++ 标准2 指定:

27.8.1 General [alg.sorting.general]

The operations in [alg.sorting] defined directly in namespace std have two versions: one that takes a function object of type Compare and one that uses an operator<.

Compare is a function object type ([function.objects]) that meets the requirements for a template parameter named BinaryPredicate ([algorithms.requirements]). The return value of the function call operation applied to an object of type Compare, when contextually converted to bool ([conv]), yields true if the first argument of the call is less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation.

For all algorithms that take Compare, there is a version that uses operator< instead. That is, comp(*i, *j) != false defaults to *i < *j != false. For algorithms other than those described in [alg.binary.search], comp shall induce a strict weak ordering on the values.

The term strict refers to the requirement of an irreflexive relation (!comp(x, x) for all x), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering. If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp and equiv both be transitive relations:

(4.1) comp(a, b) && comp(b, c) implies comp(a, c)

(4.2) equiv(a, b) && equiv(b, c) implies equiv(a, c)

给定 any floatx 的问题是以下成立:

x < NaN == falseNaN < x == false,但 x != NaN

仅考虑 float 值的子集 不是 NaN,我们可以满足要求。


1) https://en.cppreference.com/w/cpp/algorithm/min_element

2) 我在 https://eel.is/c++draft/alg.sorting.general 引用草稿,强调我的。