pxd file for the NumPy core math library (npymath)
authorLars Buitinck <larsmans@gmail.com>
Sat, 7 Sep 2013 11:30:29 +0000 (13:30 +0200)
committerLars Buitinck <larsmans@gmail.com>
Sat, 7 Sep 2013 13:19:40 +0000 (15:19 +0200)
.gitignore
Cython/Includes/numpy/__init__.pxd [moved from Cython/Includes/numpy.pxd with 100% similarity]
Cython/Includes/numpy/math.pxd [new file with mode: 0644]
runtests.py
tests/run/numpy_math.pyx [new file with mode: 0644]

index 142c8a6..1268423 100644 (file)
@@ -7,6 +7,7 @@ __pycache__
 Cython/Compiler/*.c
 Cython/Plex/*.c
 Cython/Runtime/refnanny.c
+Cython/Tempita/*.c
 
 Tools/*.elc
 
diff --git a/Cython/Includes/numpy/math.pxd b/Cython/Includes/numpy/math.pxd
new file mode 100644 (file)
index 0000000..b5325ea
--- /dev/null
@@ -0,0 +1,50 @@
+# NumPy math library
+#
+# This exports the functionality of the NumPy core math library, aka npymath,
+# which provides implementations of C99 math functions and macros for system
+# with a C89 library (such as MSVC). npymath is available with NumPy >=1.3,
+# although some functions will require later versions. The spacing function is
+# not in C99, but comes from Fortran.
+#
+# On the Cython side, the npymath functions are available without the "npy_"
+# prefix that they have in C, to make this is a drop-in replacement for
+# libc.math. The same is true for the constants, where possible.
+#
+# See the NumPy documentation for linking instructions.
+#
+# Complex number support and NumPy 2.0 half-precision functions are currently
+# not exported.
+#
+# Author: Lars Buitinck
+
+cdef extern from "numpy/npy_math.h":
+    # Floating-point classification
+    long double NAN "NPY_NAN"
+    long double INFINITY "NPY_INFINITY"
+    long double PZERO "NPY_PZERO"        # positive zero
+    long double NZERO "NPY_NZERO"        # negative zero
+
+    # These four are actually macros and work on any floating-point type.
+    bint isfinite "npy_isfinite"(long double)
+    bint isinf "npy_isinf"(long double)
+    bint isnan "npy_isnan"(long double)
+    bint signbit "npy_signbit"(long double)
+
+    double copysign "npy_copysign"(double, double)
+
+    # Math constants
+    long double E "NPY_E"
+    long double LOG2E "NPY_LOG2E"       # ln(e) / ln(2)
+    long double LOG10E "NPY_LOG10E"     # ln(e) / ln(10)
+    long double LOGE2 "NPY_LOGE2"       # ln(2)
+    long double LOGE10 "NPY_LOGE10"     # ln(10)
+    long double PI "NPY_PI"
+    long double PI_2 "NPY_PI_2"         # pi / 2
+    long double PI_4 "NPY_PI_4"         # pi / 4
+    long double NPY_1_PI                # 1 / pi; NPY_ because of ident syntax
+    long double NPY_2_PI                # 2 / pi
+    long double EULER "NPY_EULER"       # Euler constant (gamma, 0.57721)
+
+    # Low-level floating point manipulation (NumPy >=1.4)
+    double nextafter "npy_nextafter"(double x, double y)
+    double spacing "npy_spacing"(double x)
index 0311c87..f57d001 100755 (executable)
@@ -115,8 +115,15 @@ def update_linetrace_extension(ext):
 
 def update_numpy_extension(ext):
     import numpy
+    from numpy.distutils.misc_util import get_info
+
     ext.include_dirs.append(numpy.get_include())
 
+    # We need the npymath library for numpy.math.
+    # This is typically a static-only library.
+    for attr, value in get_info('npymath').items():
+        getattr(ext, attr).extend(value)
+
 def update_openmp_extension(ext):
     ext.openmp = True
     language = ext.language
diff --git a/tests/run/numpy_math.pyx b/tests/run/numpy_math.pyx
new file mode 100644 (file)
index 0000000..726cb9b
--- /dev/null
@@ -0,0 +1,55 @@
+# tag: numpy
+
+cimport numpy.math as npmath
+
+
+def test_fp_classif():
+    """
+    >>> test_fp_classif()
+    """
+
+    cdef double d_zero
+    cdef float f_zero
+
+    d_zero = -1 * 0.
+    f_zero = -1 * 0.
+
+    assert d_zero == npmath.NZERO
+    assert f_zero == npmath.NZERO
+
+    assert npmath.signbit(d_zero)
+    assert npmath.signbit(f_zero)
+
+    d_zero = 1 * 0.
+    f_zero = 1 * 0.
+
+    assert d_zero == npmath.PZERO
+    assert f_zero == npmath.PZERO
+
+    assert not npmath.signbit(d_zero)
+    assert not npmath.signbit(f_zero)
+
+    assert not npmath.isinf(d_zero)
+    assert not npmath.isinf(f_zero)
+
+    assert not npmath.isnan(d_zero)
+    assert not npmath.isnan(f_zero)
+
+    assert npmath.isinf(npmath.INFINITY)
+    assert npmath.isnan(npmath.NAN)
+
+    assert npmath.signbit(npmath.copysign(1., -1.))
+
+
+def test_nextafter():
+    """
+    >>> test_nextafter()
+    """
+
+    x = npmath.nextafter(npmath.EULER, 1)
+    assert npmath.isfinite(x)
+    assert x > npmath.EULER
+
+    x = npmath.nextafter(npmath.PI_4, -1)
+    assert npmath.isfinite(x)
+    assert x < npmath.PI_4