65

What are the most common operations that would cause a NaN, in Python, which originate while working with NumPy or SciPy?

For example:

1e500 - 1e500
>>> nan

What is the reasoning for this behavior and why does it not return 0?

12
  • 5
    You're going to have to be far more specific than that. If you're including libraries (inclusion of the numpy tag would suggest you are), then it's a completely open ended question. Since 2.6, "Behavior in special cases now aims to follow C99 Annex F. In earlier versions of Python the behavior in special cases was loosely specified." Commented Aug 26, 2014 at 12:54
  • 5
    You added the numpy tag, which is not equivalent to your question: 0/0 in Python raises a ZeroDivisionError, with numpy (using C under the hood), you'll get a NaN. Commented Aug 26, 2014 at 12:55
  • 5
    Maybe the question is broad, but it is a good question, because it answers an important problem that occurs often: you get a nan out of a code and you don't know why. If the OP rephrases the question to ask what are the most common/likely causes of a nan when working with numpy/scipy, that do not originate from other libraries, I would vote to reopen it. Commented Aug 26, 2014 at 15:26
  • 5
    I don't even see what was "too broad" about the original question. There are finitely many ways to get a NaN and knowing all of them is an excellent goal. As far as I can see, the original question was clear, sufficiently narrow, and on-topic. Commented Aug 26, 2014 at 17:44
  • 17
    For possible close voters: please visit this meta question before you cast a vote... Commented Aug 26, 2014 at 18:13

1 Answer 1

74

If you do any of the following without horsing around with the floating-point environment, you should get a NaN where you didn't have one before:

  • 0/0 (either sign on top and bottom)
  • inf/inf (either sign on top and bottom)
  • inf - inf or (-inf) + inf or inf + (-inf) or (-inf) - (-inf)
  • 0 * inf and inf * 0 (either sign on both factors)
  • sqrt(x) when x < 0
  • fmod(x, y) when y = 0 or x is infinite; here fmod is floating-point remainder.

The canonical reference for these aspects of machine arithmetic is the IEEE 754 specification. Section 7.1 describes the invalid operation exception, which is the one that is raised when you're about to get a NaN. "Exception" in IEEE 754 means something different than it does in a programming language context.

Lots of special function implementations document their behaviour at singularities of the function they're trying to implement. See the man page for atan2 and log, for instance.

You're asking specifically about NumPy and SciPy. I'm not sure whether this is simply to say "I'm asking about the machine arithmetic that happens under the hood in NumPy" or "I'm asking about eig() and stuff." I'm assuming the former, but the rest of this answer tries to make a vague connection to the higher-level functions in NumPy. The basic rule is: If the implementation of a function commits one of the above sins, you get a NaN.

For fft, for instance, you're liable to get NaNs if your input values are around 1e1010 or larger and a silent loss of precision if your input values are around 1e-1010 or smaller. Apart from truly ridiculously scaled inputs, though, you're quite safe with fft.

For things involving matrix math, NaNs can crop up (usually through the inf - inf route) if your numbers are huge or your matrix is extremely ill-conditioned. A complete discussion of how you can get screwed by numerical linear algebra is too long to belong in an answer. I'd suggest going over a numerical linear algebra book (Trefethen and Bau is popular) over the course of a few months instead.

One thing I've found useful when writing and debugging code that "shouldn't" generate NaNs is to tell the machine to trap if a NaN occurs. In GNU C, I do this:

#include <fenv.h>
feenableexcept(FE_INVALID);
Sign up to request clarification or add additional context in comments.

6 Comments

Don't forget the obvious ones... nan + <anything>, nan * <anything>, etc. (Of course, you did say "where you didn't have one before", which excludes those. Still probably worth explicitly mentioning that nan's propagate through any calculation.)
@JoeKington: Yeah, my wording sucks. That's what I meant, though; thanks for clarifying.
What version of Python did this refer to? I get a ZeroDivisionError when I divide 0/0 on Python 2.7.11 and Python 3.5.1. The same holds for 0.0 / 0.0.
@tba: This is a numpy question.
also np.arscin(-2) or every other function which is called outside where it is defined
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.