Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How remove NAN from C++ vector?

Tags:

c++

nan

I have

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

when I try x.erase(remove(x.begin(), x.end(), NAN), x.end(), I still see NAN as

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

gives

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

how can I remove the NANs so the output is below?

1 2 3 4

EDIT: x is a vector of doubles, not ints

like image 435
user5739619 Avatar asked Oct 28 '25 01:10

user5739619


2 Answers

In the weird, wild world of IEEE 754 floating point, NaN != NaN. In other words, two not-a-number values do not compare as equal to each other. So, you cannot simply let std::remove do an equality test.

You need to supply your own predicate that calls a function to determine whether or not a floating-point value is NaN. If you're targeting C++11 or later, the standard library provides such a function: std::isnan. (If not, the situation is a bit more complicated.)

Putting it all together, then, the correct code would look like this:

#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;
}

In case it got lost in all the demo code, the relevant part is just:

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

where I am passing a lambda to std::remove_if as a unary predicate. It calls std::isnan, passing in the value to check, and it returns the result, which is a Boolean indicating whether or not the value is not-a-number. If the predicate returns true, std::remove_if does the removal; otherwise, it doesn't.

Note that the logic in floating-point world is typically that NaN values are infectious. In other words, any operation involving a NaN will return NaN as a result. So, it strikes me as a bit odd that you're trying to remove all NaN values. Be careful not to just shove them under the rug as if they weren't there.

like image 139
Cody Gray Avatar answered Oct 30 '25 18:10

Cody Gray


This doesn't work, since NAN doesn't equal NAN (this is not specified by C++ standard, but in IEEE 754 standard, which your system probably conforms to). std::remove, uses equality as the condition to choose elements for removal.

Instead of std::remove, you need to use std::remove_if with a predicate using std::isnan.

like image 39
eerorika Avatar answered Oct 30 '25 18:10

eerorika



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!