How to represent inf or -inf in Cython with numpy?
Solution 1
There's no literal for it, but float
can parse it from a string:
>>> float('inf')
inf
>>> np.inf == float('inf')
True
Alternatively, math.h
may (almost certainly will) declare a macro that evaluates to inf, in which case you can just use that:
cdef extern from "math.h":
float INFINITY
(There's no clean way to check if INFINITY is defined in pure Cython, so if you want to cover all your bases you'll need to get hacky. One way of doing it is to create a small C header, say fallbackinf.h
:
#ifndef INFINITY
#define INFINITY 0
#endif
And then in your .pyx file:
cdef extern from "math.h":
float INFINITY
cdef extern from "fallbackinf.h":
pass
inf = INFINITY if INFINITY != 0 else float('inf')
(You can't assign to INFINITY, because it's an rvalue. You could do away with the ternary operator if you #defined INFINITY as 1.0/0.0 in your header, but that might raise SIGFPE, depending on your compiler.)
This is definitely in the realm of cargo cult optimisation, though.)
Solution 2
The recommended way of doing this in Cython is:
from numpy.math cimport INFINITY
Note, that this is a "cimport" rather than a regular import. This is Cython's official wrapper around NumPy's npymath
.
Solution 3
You can use Numpy's math library, see here for what's available:
cdef extern from "numpy/npy_math.h": double inf "NPY_INFINITY"
When building the Cython extension module, you need to specify the correct include directory and library to link:
>>> from numpy.distutils.misc_util import get_info >>> get_info('npymath') {'define_macros': [], 'libraries': ['npymath', 'm'], 'library_dirs': ['/usr/lib/python2.7/dist-packages/numpy/core/lib'], 'include_dirs': ['/usr/lib/python2.7/dist-packages/numpy/core/include']}
The information obtained from that function can be passed onto Python distutils, or whatever build system you use.
Admin
Updated on December 09, 2020Comments
-
Admin over 3 years
I am building an array with cython element by element. I'd like to store the constant
np.inf
(or-1 * np.inf
) in some entries. However, this will require the overhead of going back into Python to look upinf
. Is there alibc.math
equivalent of this constant? Or some other value that could easily be used that's equivalent to(-1*np.inf)
and can be used from Cython without overhead?EDIT example, you have:
cdef double value = 0 for k in xrange(...): # use -inf here -- how to avoid referring to np.inf and calling back to python? value = -1 * np.inf
-
Admin about 11 yearsbut if I use
float
within a Cython loop, will that involve calling back to Python? I edited my answer to give an example. -
Cairnarvon about 11 yearsUltimately that calls
PyFloat_AsDouble
every time, which isn't that slow, but not something you want to do more often than necessary; assign it to a constant once, outside the loop. But I've updated my answer with a different, compile-time method. -
Admin about 11 yearsThanks! your
cdef extern...
works great. Are there systems/conditions where it might not work, or should it work on any python distribution / OS? -
Cairnarvon about 11 yearsThe INFINITY macro was added in C99; if your math.h is older, it's not guaranteed to be there (though it probably still will be). In practice, it should be fine.
-
Admin about 11 yearsLast question: is it possible to programmatically check for INFINITY (if it exists) through Cython and if not, default to
float('inf')
? -
Cairnarvon about 11 yearsNot cleanly. I've added what I believe to be the easiest way to my answer.
-
hlin117 over 8 yearsI get the error
fatal error: 'numpy/npy_math.h' file not found
. Anyone else get this? -
Tom over 7 years@hlin117, nope. Probably something wrong with your setup. This answer is still the recommended way to get infinity.
-
The Unfun Cat almost 6 yearsCan you provide a cite for "the recommended way..."?
-
Tom almost 6 yearsAre you being overly pedantic? If you want to use Numpy's stuff, then this a cleaner way than using a cdef extern. If you want to use math.h, then it looks like
from libc.math cimport INFINITY
is now available, which could also work. Both of these options are better than the other two answers given, especially if you are working on any modern platform. -
Tom almost 6 yearsAlso, see the example of using
cimport
here: cython.readthedocs.io/en/latest/src/tutorial/…