如何从C ++向量中删除NAN?

时间:2019-05-31 01:00:04

标签: c++ nan

我有

std::vector<double>x={1,2,NAN,3, NAN, 4}

当我尝试x.erase(remove(x.begin(), x.end(), NAN), x.end()时,我仍然看到NAN

for (auto i:x)
    std::cout<<i<<" ";

给予

1 2 -nan(ind) 3 -nan(ind) 4

如何删除NAN,所以输出在下面?

1 2 3 4

编辑:x是双精度而不是整数的矢量

2 个答案:

答案 0 :(得分:7)

在IEEE 754浮点的怪异,狂野的世界中,NaN!= NaN。换句话说,两个非数字值 not 彼此相等。因此,您不能简单地让std::remove进行相等性测试。

您需要提供自己的谓词,该谓词调用函数来确定浮点值是否为NaN。如果您的目标是C ++ 11或更高版本,则标准库提供了这样的功能:std::isnan。 (否则,the situation is a bit more complicated。)

将它们放在一起,那么正确的代码应如下所示:

#include <cmath>
#include <vector>
#include <algorithm>
#include <iostream>


int main()
{
    std::vector<double> x = {
                              1,
                              2,
                              std::numeric_limits<double>::quiet_NaN(),
                              3,
                              std::numeric_limits<double>::quiet_NaN(),
                              4
                            };

    std::cout << "Before removing: ";
    for (auto i : x)
    {
        std::cout << i << " ";
    }
    std::cout << "\n";

    x.erase(std::remove_if(std::begin(x),
                           std::end(x),
                           [](const auto& value) { return std::isnan(value); }),
            std::end(x));

    std::cout << "After removing: ";
    for (auto i : x)
    {
        std::cout << i << " ";
    }

    return 0;
}

万一所有演示代码都迷路了,相关的部分就是:

x.erase(std::remove_if(std::begin(x),
                       std::end(x),
                       [](const auto& value) { return std::isnan(value); }),
        std::end(x));

我将lambda作为一元谓词传递给std::remove_if。它调用std::isnan,传入要检查的值,然后返回结果,该结果是一个布尔型布尔值,指示该值是否为非数字。如果谓词返回true,则std::remove_if进行删除;否则,不会。

请注意,浮点世界中的逻辑通常是NaN值具有传染性。换句话说,任何涉及NaN的操作都将返回NaN作为结果。因此,您尝试删除所有NaN值使我感到有些奇怪。注意不要只是将它们推到地毯下面,就好像它们不在那里一样。

答案 1 :(得分:2)

这是行不通的,因为NAN不等于NAN(这不是C ++标准指定的,但是在您的系统可能符合的IEEE 754标准中)。 std::remove,以相等为条件选择要删除的元素。

您需要使用std::remove来代替std::remove_if和谓词使用std::isnan