1

I'm writing a physical simulation script with Python and Numpy. All the formulas are correct, but unfortunately I still have my end results "poisoned" by some NaNs which are generated at some point during runtime. The code employs many iterations and in each iteration many functions are called and each of them performs a lot of calculations, so manually debugging every computation to find out exactly which operation generates an invalid value and when is almost impossible. To make stuff even more complicated, I'm working with large arrays of data and even a single invalid value in a large array can spread like fire when array operations are performed, being almost impossible to spot visually. Is there a simple way to tell Python to stop whenever a NaN is produced and track the last operation which caused issues?

Francesco Ghizzo
  • 57
  • 1
  • 1
  • 6
  • 2
    Why don’t you use an [`assert` statement](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement)? – Jens Apr 10 '21 at 10:25

2 Answers2

3

I think what you’re looking for is Python’s assert statement:

import math

result = ... # Some computation returning a float.
assert not math.isnan(result)  # Stops if the result is NaN.

See also the isnan() function and this question.

As per @StefanB’s comment: considering that you’re using NumPy the assertion could be something like

import numpy as np

result = ...  # Some computation returning a NumPy array.
assert not np.any(np.isnan(result))  # Stops if the result contains at least one NaN.

I also like to use the two-expression form of the assert statement to improve debugging, for example:

>>> assert not np.any(np.isnan(result)), f"Result contained NaN: {result}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Result contained NaN: [ 1.  2. nan]
Jens
  • 8,423
  • 9
  • 58
  • 78
2

NumPy offers the option to configure the handling of IEEE754 floating-point exceptions. (Note that IEEE754 exceptions are a different thing from try/except Python exceptions.) Most NaNs come from operations that generate an IEEE754 "invalid operation" exception, and you can configure NumPy to raise a FloatingPointError Python exception when an IEEE754 "invalid operation" exception is encountered:

numpy.seterr(invalid='raise')

Note that this will only affect NumPy operations, and it is not guaranteed to trigger for all cases where NaNs are produced.

user2357112
  • 260,549
  • 28
  • 431
  • 505