Different behavior of code with np.nan when jitted

This script:

import numpy as np, numba as nb

@nb.njit(fastmath=True)
def f():
  return np.nan

#@nb.njit(fastmath=True)  
def g():
  print(f(), np.isnan(f()))

g()

produces different results:

nan False

when uncommented, and:

nan True

when commented. Is there a simple explanation of this?

Interesting, for

fm = True

@nb.njit(fastmath=fm)
def g(x):
  return np.isnan(x)

I got LLVM instructions containing unordered comparison (detecting NaN)

%.12 = fcmp uno double %arg.x, 0.000000e+00
%.26 = zext i1 %.12 to i8
store i8 %.26, i8* %retptr, align 1

while for fm=True I got ‘optimized’ one:

store i8 0, i8* %retptr, align 1
1 Like

@pauljurczak Have you tried without “fastmath”?
“fastmath” allows optimizations to assume the arguments and result are not NaN.

import numpy as np, numba as nb

@nb.njit(fastmath=False)
def f():
  return np.nan

@nb.njit(fastmath=False)  
def g():
  print(f(), np.isnan(f()))

g()
# nan True

https://llvm.org/docs/LangRef.html#fast-math-flags

1 Like

Good catch, thank you. It indeed works with @nb.njit(fastmath=False) for function g(), which uses fcmp instruction. It is irrelevant for function f(), i.e.:

@nb.njit(fastmath=True)
def f():
  return np.nan

@nb.njit(fastmath=False)
def g():
  print(f(), np.isnan(f()))

works fine.

1 Like