74

When casting a NumPy Not-a-Number value as a boolean, it becomes True, e.g. as follows.

>>> import numpy as np
>>> bool(np.nan)
True

This is the exact opposite to what I would intuitively expect. Is there a sound principle underlying this behaviour?

(I suspect there might be as the same behaviour seems to occur in Octave.)

2
  • 1
    My hunch: NaN is not equal to zero, so it's true when converted to boolean. If NaN were false, then conversion of floats to booleans would take two checks, one for zero and one for NaN. (But I suspect interpreting Numpy floats as booleans is not common practice anyway...) Commented Mar 28, 2013 at 15:50
  • 9
    This is also the case in C (on which NumPy is based). From the standard: When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1. Footnote 59 explicitly states that NaNs do not compare equal to 0 and thus convert to 1. Commented Mar 28, 2013 at 15:57

7 Answers 7

47

This is in no way NumPy-specific, but is consistent with how Python treats NaNs:

In [1]: bool(float('nan'))
Out[1]: True

The rules are spelled out in the documentation.

I think it could be reasonably argued that the truth value of NaN should be False. However, this is not how the language works right now.

Sign up to request clarification or add additional context in comments.

4 Comments

TL;DR for linked docs: Python treats everything as True unless it is one of the specifically defined false cases (e.g., None, False, numeric zeroes, empty sequences, user-defined classes that return one of these, etc.).
I think it should be NaN in all types. That is, boolean should have a NaN value. NaN should never cast to a valid value.
I think the challenge with this answer and others like it (includeing @KardoPaska's TLDR) is everyone is actually interested in the why, not the that. We are playing a game of "which of these things is more like the other," and NaN seems more like"None, False, 0, empty sequences" than it does non-zero, string, non-empty. I think we would need a python core-developer around at the time to actually answer the question in the way people mean to ask it!
what made it click for me was reading about the IEEE754 convention and NaN comparisons which numpy also follows (along with many real-world CPU implementations). bool(np.nan) evaluating to True is the cleanest way (by fiat) to handle comparisons consistently, where __bool__ may be called for similar use cases. NaN is unordered here, so they simply picked a convention to follow.
9

Python truth-value testing states that the following values are considered False:

  • zero of any numeric type, for example, 0, 0L, 0.0, 0j.

Numpy probably chose to stick with this behaviour and prevent NaN from evaluating to False in a boolean context. Note however that you can use numpy.isnan to test for NaN.

Comments

5

0.0 is the only falsy float value because that's what the language designers decided would be most useful. Numpy simply follows along. (It would be weird to have bool(np.nan) be False when bool(float('nan')) is True).

I think it is probably because that's how things work with integers. Admittedly, integers have no NaN or inf types of values, but I suppose that special cases aren't special enough to break the rules.

3 Comments

It's not up to the language designers; the Numpy folks could have decided to make nan false as well.
@larsmans -- Fair enough. I didn't notice that numpy was part of the OP's question. I don't think that really changes anything though. It just makes sense for numpy to do what python does.
Should note that -0.0 is also False. It's a thing that may at first not be trivial.
4

Numpy does it because Python does it, and Python does it because C does it. But why does C do it?

IEEE 754 requires that for +0 and -0 all the exponent and fraction bits are zero. For NaN the exponent is all ones and the fraction is non-zero.

As What happens when a float is cast to/from a boolean at the first principle level? describes, the comparison to zero is likely a single fast instruction. Checking for NaNs may be more expensive.

Another possible explanation is that this conversion has existed even before NaNs were introduced. It wasn't immediately updated, and now it's too late to change it.

2 Comments

Sorry about the speculative answer! I just felt like the existing answers basically said "just because".
The only useful answer :)
2

Numpy follows the python standard for truth testing here, any numeric type evaluates to False if and only if its numerical value is zero.

Note that truth testing with NaN values can be unintuitive in other ways as well (e.g., nan == nan evaluates to False).

Comments

0

This is usually needed when testing variables for np.nan. While np.nan is not np.nan fails (evaluates to False), the np.isnan function works (evaluates to True, so can be used to test for np.nan):

np.isnan(np.nan)

True

Comments

0

You may use np.isnan(foo) to do Boolean checks on NumPy nan values.

In [1]: np.isnan(np.nan)
Out[1]: True

In [1]: not np.isnan(np.nan)
Out[1]: False

https://numpy.org/doc/stable/reference/generated/numpy.isnan.html

1 Comment

That is correct but irrelevant to the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.