numba icon indicating copy to clipboard operation
numba copied to clipboard

isfinite(inf) raises FloatingPointError in vectorized functions

Open aerobio opened this issue 1 year ago • 5 comments

The following works as expected:

@nb.njit
def finite(x):
    return math.isfinite(x)
>>> finite(1.)
True
>>> finite(math.nan)
False
>>> finite(math.inf)
False

However, this vectorized version raises an exception when it receives inf:

@nb.vectorize
def finite(x):
    return math.isfinite(x)
>>> finite(1.)
True
>>> finite(math.nan)
False
>>> finite(math.inf)
FloatingPointError: invalid value encountered in finite

It is interesting to notice that the behavior changes depending on np.seterr() settings:

>>> np.seterr(all='raise')
>>> finite(math.inf)
FloatingPointError: invalid value encountered in finite [...]

>>> np.seterr(all='warn')
>>> finite(math.inf)
RuntimeWarning: invalid value encountered in finite [...]
False

>>> np.seterr(all='ignore')
>>> finite(math.inf)
False

The same happens in guvectorized functions.

I understand isfinite(inf) should never raise an exception or warning, according to the behavior of math.isfinite() or np.isfinite(), or its own behavior in the non-vectorized version.

Using Numba 0.60.0 and Python 3.10.12.

aerobio avatar Aug 08 '24 10:08 aerobio

For example, when converting floating point values to integers, an alternative to checking isfinite() would be to catch the exception raised by int(nan) or int(inf), but int(inf) does not raise OverflowError (#6044).

aerobio avatar Aug 08 '24 10:08 aerobio

Thanks for the report. I can reproduce similar behaviour with:

from numba import njit, vectorize
import math
import numpy as np

np.seterr(all='raise')


@njit
def finite(x):
    return math.isfinite(x)


finite(1.0)
finite(math.nan)
finite(math.inf)


@vectorize
def vectorize_finite(x):
    return math.isfinite(x)


vectorize_finite(1.0)
vectorize_finite(math.nan)
vectorize_finite(math.inf)

gmarkall avatar Aug 08 '24 11:08 gmarkall

The implementation if is_finite (in numba/cpython/mathimpl.py) might be setting an error flag:

 56 def is_finite(builder, val):
 57     """
 58     Return a condition testing whether *val* is a finite.
 59     """
 60     # is_finite(x)  <=>  x - x != NaN
 61     val_minus_val = builder.fsub(val, val)
 62     return builder.fcmp_ordered('ord', val_minus_val, val_minus_val)

gmarkall avatar Aug 13 '24 14:08 gmarkall

Newer llvm has https://llvm.org/docs/LangRef.html#llvm-is-fpclass-intrinsic

sklam avatar Aug 13 '24 14:08 sklam

Also in LLVM 15: https://releases.llvm.org/15.0.0/docs/LangRef.html#llvm-is-fpclass-intrinsic

gmarkall avatar Aug 13 '24 14:08 gmarkall