diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2010-12-01 20:12:18 -0700 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2010-12-01 20:12:18 -0700 |
commit | 2ee163942a7461b14f53523dadbda7b4e5e18efd (patch) | |
tree | 39b447663a83c021c34b8cdf32a3644e1bfe9ebc | |
parent | af84876fac13ac2e4e44ac0cae599fe9d6e68643 (diff) | |
parent | c6f8dbbd240ada8d0edd0527cd218cfc46deec41 (diff) | |
download | numpy-2ee163942a7461b14f53523dadbda7b4e5e18efd.tar.gz |
Merge branch 'm-paradox-implement_half_dtype'
40 files changed, 2956 insertions, 757 deletions
diff --git a/doc/source/reference/arrays.dtypes.rst b/doc/source/reference/arrays.dtypes.rst index c1b09f609..c89a282f4 100644 --- a/doc/source/reference/arrays.dtypes.rst +++ b/doc/source/reference/arrays.dtypes.rst @@ -137,7 +137,7 @@ What can be converted to a data-type object is described below: Array-scalar types - The 21 built-in :ref:`array scalar type objects + The 24 built-in :ref:`array scalar type objects <arrays.scalars.built-in>` all convert to an associated data-type object. This is true for their sub-classes as well. diff --git a/doc/source/reference/arrays.scalars.rst b/doc/source/reference/arrays.scalars.rst index 62e22146a..0d5d3f59e 100644 --- a/doc/source/reference/arrays.scalars.rst +++ b/doc/source/reference/arrays.scalars.rst @@ -12,7 +12,7 @@ convenient in applications that don't need to be concerned with all the ways data can be represented in a computer. For scientific computing, however, more control is often needed. -In NumPy, there are 21 new fundamental Python types to describe +In NumPy, there are 24 new fundamental Python types to describe different types of scalars. These type descriptors are mostly based on the types available in the C language that CPython is written in, with several additional types compatible with Python's types. @@ -138,10 +138,12 @@ Unsigned integers: Floating-point numbers: =================== ============================= =============== +:class:`half` ``'e'`` :class:`single` compatible: C float ``'f'`` :class:`double` compatible: C double :class:`float_` compatible: Python float ``'d'`` :class:`longfloat` compatible: C long float ``'g'`` +:class:`float16` 16 bits :class:`float32` 32 bits :class:`float64` 64 bits :class:`float96` 96 bits, platform? diff --git a/doc/source/reference/c-api.coremath.rst b/doc/source/reference/c-api.coremath.rst index 5c50f36e4..6584f216d 100644 --- a/doc/source/reference/c-api.coremath.rst +++ b/doc/source/reference/c-api.coremath.rst @@ -18,7 +18,7 @@ library contains most math-related C99 functionality, which can be used on platforms where C99 is not well supported. The core math functions have the same API as the C99 ones, except for the npy_* prefix. -The available functions are defined in npy_math.h - please refer to this header +The available functions are defined in <numpy/npy_math.h> - please refer to this header when in doubt. Floating point classification @@ -55,7 +55,7 @@ Floating point classification This is a macro, and is equivalent to C99 isfinite: works for single, double and extended precision, and return a non 0 value is x is neither a - NaN or a infinity. + NaN nor an infinity. .. cfunction:: int npy_isinf(x) @@ -181,3 +181,200 @@ compile and link options to your extension in your setup.py: In other words, the usage of info is exactly the same as when using blas_info and co. + +Half-precision functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.0.0 + +The header file <numpy/halffloat.h> provides functions to work with +IEEE 754-2008 16-bit floating point values. While this format is +not typically used for numerical computations, it is useful for +storing values which require floating point but do not need much precision. +It can also be used as an educational tool to understand the nature +of floating point round-off error. + +Like for other types, NumPy includes a typedef npy_half for the 16 bit +float. Unlike for most of the other types, you cannot use this as a +normal type in C, since is is a typedef for npy_uint16. For example, +1.0 looks like 0x3c00 to C, and if you do an equality comparison +between the different signed zeros, you will get -0.0 != 0.0 +(0x8000 != 0x0000), which is incorrect. + +For these reasons, NumPy provides an API to work with npy_half values +accessible by including <numpy/halffloat.h> and linking to 'npymath'. +For functions that are not provided directly, such as the arithmetic +operations, the preferred method is to convert to float +or double and back again, as in the following example. + +.. code-block:: c + + npy_half sum(int n, npy_half *array) { + float ret = 0; + while(n--) { + ret += npy_half_to_float(*array++); + } + return npy_float_to_half(ret); + } + +External Links: + +* `754-2008 IEEE Standard for Floating-Point Arithmetic`__ +* `Half-precision Float Wikipedia Article`__. +* `OpenGL Half Float Pixel Support`__ +* `The OpenEXR image format`__. + +__ http://ieeexplore.ieee.org/servlet/opac?punumber=4610933 +__ http://en.wikipedia.org/wiki/Half_precision_floating-point_format +__ http://www.opengl.org/registry/specs/ARB/half_float_pixel.txt +__ http://www.openexr.com/about.html + +.. cvar:: NPY_HALF_ZERO + + This macro is defined to positive zero. + +.. cvar:: NPY_HALF_PZERO + + This macro is defined to positive zero. + +.. cvar:: NPY_HALF_NZERO + + This macro is defined to negative zero. + +.. cvar:: NPY_HALF_ONE + + This macro is defined to 1.0. + +.. cvar:: NPY_HALF_NEGONE + + This macro is defined to -1.0. + +.. cvar:: NPY_HALF_PINF + + This macro is defined to +inf. + +.. cvar:: NPY_HALF_NINF + + This macro is defined to -inf. + +.. cvar:: NPY_HALF_NAN + + This macro is defined to a NaN value, guaranteed to have its sign bit unset. + +.. cfunction:: float npy_half_to_float(npy_half h) + + Converts a half-precision float to a single-precision float. + +.. cfunction:: double npy_half_to_double(npy_half h) + + Converts a half-precision float to a double-precision float. + +.. cfunction:: npy_half npy_float_to_half(float f) + + Converts a single-precision float to a half-precision float. The + value is rounded to the nearest representable half, with ties going + to the nearest even. If the value is too small or too big, the + system's floating point underflow or overflow bit will be set. + +.. cfunction:: npy_half npy_double_to_half(double d) + + Converts a double-precision float to a half-precision float. The + value is rounded to the nearest representable half, with ties going + to the nearest even. If the value is too small or too big, the + system's floating point underflow or overflow bit will be set. + +.. cfunction:: int npy_half_eq(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 == h2). + +.. cfunction:: int npy_half_ne(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 != h2). + +.. cfunction:: int npy_half_le(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 <= h2). + +.. cfunction:: int npy_half_lt(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 < h2). + +.. cfunction:: int npy_half_ge(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 >= h2). + +.. cfunction:: int npy_half_gt(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 > h2). + +.. cfunction:: int npy_half_eq_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 == h2). If + a value is NaN, the result is undefined. + +.. cfunction:: int npy_half_lt_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 < h2). If + a value is NaN, the result is undefined. + +.. cfunction:: int npy_half_le_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 <= h2). If + a value is NaN, the result is undefined. + +.. cfunction:: int npy_half_iszero(npy_half h) + + Tests whether the half-precision float has a value equal to zero. This may be slightly + faster than calling npy_half_eq(h, NPY_ZERO). + +.. cfunction:: int npy_half_isnan(npy_half h) + + Tests whether the half-precision float is a NaN. + +.. cfunction:: int npy_half_isinf(npy_half h) + + Tests whether the half-precision float is plus or minus Inf. + +.. cfunction:: int npy_half_isfinite(npy_half h) + + Tests whether the half-precision float is finite (not NaN or Inf). + +.. cfunction:: int npy_half_signbit(npy_half h) + + Returns 1 is h is negative, 0 otherwise. + +.. cfunction:: npy_half npy_half_copysign(npy_half x, npy_half y) + + Returns the value of x with the sign bit copied from y. Works for any value, + including Inf and NaN. + +.. cfunction:: npy_half npy_half_spacing(npy_half h) + + This is the same for half-precision float as npy_spacing and npy_spacingf + described in the low-level floating point section. + +.. cfunction:: npy_half npy_half_nextafter(npy_half x, npy_half y) + + This is the same for half-precision float as npy_nextafter and npy_nextafterf + described in the low-level floating point section. + +.. cfunction:: npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f) + + Low-level function which converts a 32-bit single-precision float, stored + as a uint32, into a 16-bit half-precision float. + +.. cfunction:: npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d) + + Low-level function which converts a 64-bit double-precision float, stored + as a uint64, into a 16-bit half-precision float. + +.. cfunction:: npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h) + + Low-level function which converts a 16-bit half-precision float + into a 32-bit single-precision float, stored as a uint32. + +.. cfunction:: npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h) + + Low-level function which converts a 16-bit half-precision float + into a 64-bit double-precision float, stored as a uint64. + diff --git a/doc/source/reference/c-api.dtype.rst b/doc/source/reference/c-api.dtype.rst index 569a4ccb3..01f5260de 100644 --- a/doc/source/reference/c-api.dtype.rst +++ b/doc/source/reference/c-api.dtype.rst @@ -3,7 +3,7 @@ Data Type API .. sectionauthor:: Travis E. Oliphant -The standard array can have 21 different data types (and has some +The standard array can have 24 different data types (and has some support for adding your own types). These data types all have an enumerated type, an enumerated type-character, and a corresponding array scalar Python type object (placed in a hierarchy). There are @@ -25,15 +25,16 @@ select the precision desired. Enumerated Types ---------------- -There is a list of enumerated types defined providing the basic 21 +There is a list of enumerated types defined providing the basic 24 data types plus some useful generic names. Whenever the code requires a type number, one of these enumerated types is requested. The types are all called :cdata:`NPY_{NAME}` where ``{NAME}`` can be **BOOL**, **BYTE**, **UBYTE**, **SHORT**, **USHORT**, **INT**, **UINT**, **LONG**, **ULONG**, **LONGLONG**, **ULONGLONG**, - **FLOAT**, **DOUBLE**, **LONGDOUBLE**, **CFLOAT**, **CDOUBLE**, - **CLONGDOUBLE**, **OBJECT**, **STRING**, **UNICODE**, **VOID** + **HALF**, **FLOAT**, **DOUBLE**, **LONGDOUBLE**, **CFLOAT**, + **CDOUBLE**, **CLONGDOUBLE**, **DATETIME**, **TIMEDELTA**, + **OBJECT**, **STRING**, **UNICODE**, **VOID** **NTYPES**, **NOTYPE**, **USERDEF**, **DEFAULT_TYPE** @@ -44,8 +45,9 @@ is :cdata:`NPY_{NAME}LTR` where ``{NAME}`` can be **BOOL**, **BYTE**, **UBYTE**, **SHORT**, **USHORT**, **INT**, **UINT**, **LONG**, **ULONG**, **LONGLONG**, **ULONGLONG**, - **FLOAT**, **DOUBLE**, **LONGDOUBLE**, **CFLOAT**, **CDOUBLE**, - **CLONGDOUBLE**, **OBJECT**, **STRING**, **VOID** + **HALF**, **FLOAT**, **DOUBLE**, **LONGDOUBLE**, **CFLOAT**, + **CDOUBLE**, **CLONGDOUBLE**, **DATETIME**, **TIMEDELTA**, + **OBJECT**, **STRING**, **VOID** **INTP**, **UINTP** diff --git a/doc/source/reference/c-api.ufunc.rst b/doc/source/reference/c-api.ufunc.rst index 384a69cf7..f299251cb 100644 --- a/doc/source/reference/c-api.ufunc.rst +++ b/doc/source/reference/c-api.ufunc.rst @@ -234,18 +234,27 @@ structure. .. cfunction:: void PyUFunc_G_G(char** args, npy_intp* dimensions, npy_intp* steps, void* func) +.. cfunction:: void PyUFunc_e_e(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + +.. cfunction:: void PyUFunc_e_e_As_f_f(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + +.. cfunction:: void PyUFunc_e_e_As_d_d(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + Type specific, core 1-d functions for ufuncs where each calculation is obtained by calling a function taking one input argument and returning one output. This function is passed in ``func``. The letters correspond to dtypechar's of the supported - data types ( ``f`` - float, ``d`` - double, ``g`` - long double, - ``F`` - cfloat, ``D`` - cdouble, ``G`` - clongdouble). The - argument *func* must support the same signature. The _As_X_X - variants assume ndarray's of one data type but cast the values to - use an underlying function that takes a different data type. Thus, - :cfunc:`PyUFunc_f_f_As_d_d` uses ndarrays of data type :cdata:`NPY_FLOAT` - but calls out to a C-function that takes double and returns - double. + data types ( ``e`` - half, ``f`` - float, ``d`` - double, + ``g`` - long double, ``F`` - cfloat, ``D`` - cdouble, + ``G`` - clongdouble). The argument *func* must support the same + signature. The _As_X_X variants assume ndarray's of one data type + but cast the values to use an underlying function that takes a + different data type. Thus, :cfunc:`PyUFunc_f_f_As_d_d` uses + ndarrays of data type :cdata:`NPY_FLOAT` but calls out to a + C-function that takes double and returns double. .. cfunction:: void PyUFunc_ff_f_As_dd_d(char** args, npy_intp* dimensions, npy_intp* steps, void* func) @@ -271,6 +280,15 @@ structure. .. cfunction:: void PyUFunc_GG_G(char** args, npy_intp* dimensions, npy_intp* steps, void* func) +.. cfunction:: void PyUFunc_ee_e(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + +.. cfunction:: void PyUFunc_ee_e_As_ff_f(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + +.. cfunction:: void PyUFunc_ee_e_As_dd_d(char** args, npy_intp* dimensions, + npy_intp* steps, void* func) + Type specific, core 1-d functions for ufuncs where each calculation is obtained by calling a function taking two input arguments and returning one output. The underlying function to diff --git a/doc/source/reference/figures/dtype-hierarchy.dia b/doc/source/reference/figures/dtype-hierarchy.dia Binary files differindex 65379b880..62e925cfd 100644 --- a/doc/source/reference/figures/dtype-hierarchy.dia +++ b/doc/source/reference/figures/dtype-hierarchy.dia diff --git a/doc/source/reference/figures/dtype-hierarchy.png b/doc/source/reference/figures/dtype-hierarchy.png Binary files differindex 5722ac527..6c45758b1 100644 --- a/doc/source/reference/figures/dtype-hierarchy.png +++ b/doc/source/reference/figures/dtype-hierarchy.png diff --git a/doc/source/reference/ufuncs.rst b/doc/source/reference/ufuncs.rst index 77269be58..dedbf2929 100644 --- a/doc/source/reference/ufuncs.rst +++ b/doc/source/reference/ufuncs.rst @@ -207,7 +207,7 @@ implemented by the question of when a data type can be cast "safely" to another data type. The answer to this question can be determined in Python with a function call: :func:`can_cast(fromtype, totype) <can_cast>`. The Figure below shows the results of this call for -the 21 internally supported types on the author's 32-bit system. You +the 24 internally supported types on the author's 64-bit system. You can generate this table for your system with the code given in the Figure. .. admonition:: Figure @@ -224,34 +224,38 @@ can generate this table for your system with the code given in the Figure. ... print int(np.can_cast(row, col)), ... print >>> print_table(np.typecodes['All']) - X ? b h i l q p B H I L Q P f d g F D G S U V O - ? 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - b 0 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 - h 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 - i 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 - l 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 - q 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 - p 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 - B 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - H 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - I 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 - L 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 - Q 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 1 1 1 1 1 - P 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 - f 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 - d 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 - g 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 - F 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 - D 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 - G 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 - S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 - U 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 - V 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 - O 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + X ? b h i l q p B H I L Q P e f d g F D G S U V O M m + ? 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + b 0 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 + h 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 + i 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + l 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + q 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + p 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + B 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 + H 0 0 0 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 + I 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + L 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + Q 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + P 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + e 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 + f 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 + d 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + g 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 0 0 + F 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 + D 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 + G 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 + S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 + U 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 + V 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + O 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + M 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 + m 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 + You should note that, while included in the table for completeness, the 'S', 'U', and 'V' types cannot be operated on by ufuncs. Also, -note that on a 64-bit system the integer types may have different +note that on a 32-bit system the integer types may have different sizes, resulting in a slightly altered table. Mixed scalar-array operations use a different set of casting rules diff --git a/doc/source/user/c-info.beyond-basics.rst b/doc/source/user/c-info.beyond-basics.rst index 563467e72..5ff92a122 100644 --- a/doc/source/user/c-info.beyond-basics.rst +++ b/doc/source/user/c-info.beyond-basics.rst @@ -389,7 +389,7 @@ register ufuncs for user-defined data-types. User-defined data-types ======================= -NumPy comes with 21 builtin data-types. While this covers a large +NumPy comes with 24 builtin data-types. While this covers a large majority of possible use cases, it is conceivable that a user may have a need for an additional data-type. There is some support for adding an additional data-type into the NumPy system. This additional data- diff --git a/numpy/core/SConscript b/numpy/core/SConscript index bb4ec36fc..5f7212387 100644 --- a/numpy/core/SConscript +++ b/numpy/core/SConscript @@ -408,7 +408,8 @@ env.Prepend(CPPPATH = ['src/private', 'include', '.', 'include/numpy']) # npymath core lib npymath_src = [env.GenerateFromTemplate(pjoin('src', 'npymath', 'npy_math.c.src')), env.GenerateFromTemplate(pjoin('src', 'npymath', 'npy_math_complex.c.src')), - env.GenerateFromTemplate(pjoin('src', 'npymath', 'ieee754.c.src'))] + env.GenerateFromTemplate(pjoin('src', 'npymath', 'ieee754.c.src')), + pjoin('src', 'npymath', 'halffloat.c')] env.DistutilsInstalledStaticExtLibrary("npymath", npymath_src, install_dir='lib') env.Prepend(LIBS=["npymath"]) env.Prepend(LIBPATH=["."]) diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 5d19534e4..9382b1fae 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -31,10 +31,16 @@ class TypeDescription(object): The typecode(s) of the inputs. out : str or None, optional The typecode(s) of the outputs. + astype : dict or None, optional + If astype['x'] is 'y', uses PyUFunc_x_x_As_y_y/PyUFunc_xx_x_As_yy_y + instead of PyUFunc_x_x/PyUFunc_xx_x. """ - def __init__(self, type, f=None, in_=None, out=None): + def __init__(self, type, f=None, in_=None, out=None, astype=None): self.type = type self.func_data = f + if astype is None: + astype = {} + self.astype_dict = astype if in_ is not None: in_ = in_.replace('P', type) self.in_ = in_ @@ -49,8 +55,9 @@ class TypeDescription(object): if self.out is None: self.out = self.type * nout assert len(self.out) == nout + self.astype = self.astype_dict.get(self.type, None) -_fdata_map = dict(f='npy_%sf', d='npy_%s', g='npy_%sl', +_fdata_map = dict(e='npy_%sf', f='npy_%sf', d='npy_%s', g='npy_%sl', F='nc_%sf', D='nc_%s', G='nc_%sl') def build_func_data(types, f): func_data = [] @@ -59,7 +66,7 @@ def build_func_data(types, f): func_data.append(d) return func_data -def TD(types, f=None, in_=None, out=None): +def TD(types, f=None, astype=None, in_=None, out=None): if f is not None: if isinstance(f, str): func_data = build_func_data(types, f) @@ -78,7 +85,7 @@ def TD(types, f=None, in_=None, out=None): out = (None,) * len(types) tds = [] for t, fd, i, o in zip(types, func_data, in_, out): - tds.append(TypeDescription(t, f=fd, in_=i, out=o)) + tds.append(TypeDescription(t, f=fd, in_=i, out=o, astype=astype)) return tds class Ufunc(object): @@ -166,6 +173,7 @@ chartoname = {'?': 'bool', 'L': 'ulong', 'q': 'longlong', 'Q': 'ulonglong', + 'e': 'half', 'f': 'float', 'd': 'double', 'g': 'longdouble', @@ -180,7 +188,7 @@ chartoname = {'?': 'bool', 'P': 'OBJECT', } -all = '?bBhHiIlLqQfdgFDGOMm' +all = '?bBhHiIlLqQefdgFDGOMm' O = 'O' P = 'P' ints = 'bBhHiIlLqQ' @@ -188,7 +196,7 @@ times = 'Mm' intsO = ints + O bints = '?' + ints bintsO = bints + O -flts = 'fdg' +flts = 'efdg' fltsO = flts + O fltsP = flts + P cmplx = 'FDG' @@ -217,6 +225,10 @@ for code in 'bhilq': uint64 = english_upper(code) break +# This dictionary describes all the ufunc implementations, generating +# all the function names and their corresponding ufunc signatures. TD is +# an object which expands a list of character codes into an array of +# TypeDescriptions. defdict = { 'add' : Ufunc(2, 1, Zero, @@ -274,7 +286,7 @@ defdict = { Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.fmod'), TD(ints), - TD(flts, f='fmod'), + TD(flts, f='fmod', astype={'e':'f'}), TD(P, f='fmod'), ), 'square' : @@ -299,7 +311,7 @@ defdict = { Ufunc(2, 1, One, docstrings.get('numpy.core.umath.power'), TD(ints), - TD(inexact, f='pow'), + TD(inexact, f='pow', astype={'e':'f'}), TD(O, f='npy_ObjectPower'), ), 'absolute' : @@ -407,12 +419,12 @@ defdict = { 'logaddexp' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.logaddexp'), - TD(flts, f="logaddexp") + TD(flts, f="logaddexp", astype={'e':'f'}) ), 'logaddexp2' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.logaddexp2'), - TD(flts, f="logaddexp2") + TD(flts, f="logaddexp2", astype={'e':'f'}) ), # FIXME: decide if the times should have the bitwise operations. 'bitwise_and' : @@ -454,177 +466,177 @@ defdict = { 'degrees' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.degrees'), - TD(fltsP, f='degrees'), + TD(fltsP, f='degrees', astype={'e':'f'}), ), 'rad2deg' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.rad2deg'), - TD(fltsP, f='rad2deg'), + TD(fltsP, f='rad2deg', astype={'e':'f'}), ), 'radians' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.radians'), - TD(fltsP, f='radians'), + TD(fltsP, f='radians', astype={'e':'f'}), ), 'deg2rad' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.deg2rad'), - TD(fltsP, f='deg2rad'), + TD(fltsP, f='deg2rad', astype={'e':'f'}), ), 'arccos' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arccos'), - TD(inexact, f='acos'), + TD(inexact, f='acos', astype={'e':'f'}), TD(P, f='arccos'), ), 'arccosh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arccosh'), - TD(inexact, f='acosh'), + TD(inexact, f='acosh', astype={'e':'f'}), TD(P, f='arccosh'), ), 'arcsin' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arcsin'), - TD(inexact, f='asin'), + TD(inexact, f='asin', astype={'e':'f'}), TD(P, f='arcsin'), ), 'arcsinh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arcsinh'), - TD(inexact, f='asinh'), + TD(inexact, f='asinh', astype={'e':'f'}), TD(P, f='arcsinh'), ), 'arctan' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arctan'), - TD(inexact, f='atan'), + TD(inexact, f='atan', astype={'e':'f'}), TD(P, f='arctan'), ), 'arctanh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arctanh'), - TD(inexact, f='atanh'), + TD(inexact, f='atanh', astype={'e':'f'}), TD(P, f='arctanh'), ), 'cos' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.cos'), - TD(inexact, f='cos'), + TD(inexact, f='cos', astype={'e':'f'}), TD(P, f='cos'), ), 'sin' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sin'), - TD(inexact, f='sin'), + TD(inexact, f='sin', astype={'e':'f'}), TD(P, f='sin'), ), 'tan' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.tan'), - TD(inexact, f='tan'), + TD(inexact, f='tan', astype={'e':'f'}), TD(P, f='tan'), ), 'cosh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.cosh'), - TD(inexact, f='cosh'), + TD(inexact, f='cosh', astype={'e':'f'}), TD(P, f='cosh'), ), 'sinh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sinh'), - TD(inexact, f='sinh'), + TD(inexact, f='sinh', astype={'e':'f'}), TD(P, f='sinh'), ), 'tanh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.tanh'), - TD(inexact, f='tanh'), + TD(inexact, f='tanh', astype={'e':'f'}), TD(P, f='tanh'), ), 'exp' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.exp'), - TD(inexact, f='exp'), + TD(inexact, f='exp', astype={'e':'f'}), TD(P, f='exp'), ), 'exp2' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.exp2'), - TD(inexact, f='exp2'), + TD(inexact, f='exp2', astype={'e':'f'}), TD(P, f='exp2'), ), 'expm1' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.expm1'), - TD(inexact, f='expm1'), + TD(inexact, f='expm1', astype={'e':'f'}), TD(P, f='expm1'), ), 'log' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log'), - TD(inexact, f='log'), + TD(inexact, f='log', astype={'e':'f'}), TD(P, f='log'), ), 'log2' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log2'), - TD(inexact, f='log2'), + TD(inexact, f='log2', astype={'e':'f'}), TD(P, f='log2'), ), 'log10' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log10'), - TD(inexact, f='log10'), + TD(inexact, f='log10', astype={'e':'f'}), TD(P, f='log10'), ), 'log1p' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log1p'), - TD(inexact, f='log1p'), + TD(inexact, f='log1p', astype={'e':'f'}), TD(P, f='log1p'), ), 'sqrt' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sqrt'), - TD(inexact, f='sqrt'), + TD(inexact, f='sqrt', astype={'e':'f'}), TD(P, f='sqrt'), ), 'ceil' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.ceil'), - TD(flts, f='ceil'), + TD(flts, f='ceil', astype={'e':'f'}), TD(P, f='ceil'), ), 'trunc' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.trunc'), - TD(flts, f='trunc'), + TD(flts, f='trunc', astype={'e':'f'}), TD(P, f='trunc'), ), 'fabs' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.fabs'), - TD(flts, f='fabs'), + TD(flts, f='fabs', astype={'e':'f'}), TD(P, f='fabs'), ), 'floor' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.floor'), - TD(flts, f='floor'), + TD(flts, f='floor', astype={'e':'f'}), TD(P, f='floor'), ), 'rint' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.rint'), - TD(inexact, f='rint'), + TD(inexact, f='rint', astype={'e':'f'}), TD(P, f='rint'), ), 'arctan2' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.arctan2'), - TD(flts, f='atan2'), + TD(flts, f='atan2', astype={'e':'f'}), TD(P, f='arctan2'), ), 'remainder' : @@ -636,7 +648,7 @@ defdict = { 'hypot' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.hypot'), - TD(flts, f='hypot'), + TD(flts, f='hypot', astype={'e':'f'}), TD(P, f='hypot'), ), 'isnan' : @@ -692,7 +704,8 @@ def indent(st,spaces): indented = re.sub(r' +$',r'',indented) return indented -chartotype1 = {'f': 'f_f', +chartotype1 = {'e': 'e_e', + 'f': 'f_f', 'd': 'd_d', 'g': 'g_g', 'F': 'F_F', @@ -701,7 +714,8 @@ chartotype1 = {'f': 'f_f', 'O': 'O_O', 'P': 'O_O_method'} -chartotype2 = {'f': 'ff_f', +chartotype2 = {'e': 'ee_e', + 'f': 'ff_f', 'd': 'dd_d', 'g': 'gg_g', 'F': 'FF_F', @@ -739,8 +753,11 @@ def make_arrays(funcdict): for t in uf.type_descriptions: if t.func_data not in (None, UsesArraysAsData): funclist.append('NULL') - astr = '%s_functions[%d] = PyUFunc_%s;' % \ - (name, k, thedict[t.type]) + astype = '' + if not t.astype is None: + astype = '_As_%s' % thedict[t.astype] + astr = '%s_functions[%d] = PyUFunc_%s%s;' % \ + (name, k, thedict[t.type], astype) code2list.append(astr) if t.type == 'O': astr = '%s_data[%d] = (void *) %s;' % \ diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py index 2cc6411d5..9474a131a 100644 --- a/numpy/core/code_generators/numpy_api.py +++ b/numpy/core/code_generators/numpy_api.py @@ -64,6 +64,7 @@ multiarray_types_api = { 'PyTimeIntegerArrType_Type': 39, 'PyDatetimeArrType_Type': 40, 'PyTimedeltaArrType_Type': 41, + 'PyHalfArrType_Type': 221, } #define NPY_NUMUSERTYPES (*(int *)PyArray_API[6]) @@ -290,6 +291,12 @@ ufunc_funcs_api = { 'PyUFunc_ReplaceLoopBySignature': 30, 'PyUFunc_FromFuncAndDataAndSignature': 31, 'PyUFunc_SetUsesArraysAsData': 32, + 'PyUFunc_e_e': 33, + 'PyUFunc_e_e_As_f_f': 34, + 'PyUFunc_e_e_As_d_d': 35, + 'PyUFunc_ee_e': 36, + 'PyUFunc_ee_e_As_ff_f': 37, + 'PyUFunc_ee_e_As_dd_d': 38, } # List of all the dicts which define the C API diff --git a/numpy/core/getlimits.py b/numpy/core/getlimits.py index 4fa020e86..198862d6a 100644 --- a/numpy/core/getlimits.py +++ b/numpy/core/getlimits.py @@ -131,6 +131,10 @@ class finfo(object): itype = ntypes.longlong fmt = '%s' precname = 'long double' + elif dtype is ntypes.half: + itype = ntypes.int16 + fmt = '%12.5e' + precname = 'half' else: raise ValueError, repr(dtype) diff --git a/numpy/core/include/numpy/arrayscalars.h b/numpy/core/include/numpy/arrayscalars.h index 1f7f3c7e3..64450e713 100644 --- a/numpy/core/include/numpy/arrayscalars.h +++ b/numpy/core/include/numpy/arrayscalars.h @@ -71,6 +71,12 @@ typedef struct { typedef struct { PyObject_HEAD + npy_half obval; +} PyHalfScalarObject; + + +typedef struct { + PyObject_HEAD float obval; } PyFloatScalarObject; diff --git a/numpy/core/include/numpy/halffloat.h b/numpy/core/include/numpy/halffloat.h new file mode 100644 index 000000000..c6bb726bc --- /dev/null +++ b/numpy/core/include/numpy/halffloat.h @@ -0,0 +1,68 @@ +#ifndef __NPY_HALFFLOAT_H__ +#define __NPY_HALFFLOAT_H__ + +#include <Python.h> +#include <numpy/ndarraytypes.h> +#include <numpy/npy_math.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Half-precision routines + */ + +/* Conversions */ +float npy_half_to_float(npy_half h); +double npy_half_to_double(npy_half h); +npy_half npy_float_to_half(float f); +npy_half npy_double_to_half(double d); +/* Comparisons */ +int npy_half_eq(npy_half h1, npy_half h2); +int npy_half_ne(npy_half h1, npy_half h2); +int npy_half_le(npy_half h1, npy_half h2); +int npy_half_lt(npy_half h1, npy_half h2); +int npy_half_ge(npy_half h1, npy_half h2); +int npy_half_gt(npy_half h1, npy_half h2); +/* faster *_nonan variants for when you know h1 and h2 are not NaN */ +int npy_half_eq_nonan(npy_half h1, npy_half h2); +int npy_half_lt_nonan(npy_half h1, npy_half h2); +int npy_half_le_nonan(npy_half h1, npy_half h2); +/* Miscellaneous functions */ +int npy_half_iszero(npy_half h); +int npy_half_isnan(npy_half h); +int npy_half_isinf(npy_half h); +int npy_half_isfinite(npy_half h); +int npy_half_signbit(npy_half h); +npy_half npy_half_copysign(npy_half x, npy_half y); +npy_half npy_half_spacing(npy_half h); +npy_half npy_half_nextafter(npy_half x, npy_half y); + +/* + * Half-precision constants + */ + +#define NPY_HALF_ZERO (0x0000u) +#define NPY_HALF_PZERO (0x0000u) +#define NPY_HALF_NZERO (0x8000u) +#define NPY_HALF_ONE (0x3c00u) +#define NPY_HALF_NEGONE (0xbc00u) +#define NPY_HALF_PINF (0x7c00u) +#define NPY_HALF_NINF (0xfc00u) +#define NPY_HALF_NAN (0x7e00u) + +/* + * Bit-level conversions + */ + +npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f); +npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d); +npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h); +npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h index e64ddea6d..98d02287a 100644 --- a/numpy/core/include/numpy/ndarraytypes.h +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -65,10 +65,10 @@ enum NPY_TYPES { NPY_BOOL=0, NPY_INT, NPY_UINT, NPY_LONG, NPY_ULONG, NPY_LONGLONG, NPY_ULONGLONG, - NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, + NPY_HALF, NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, NPY_DATETIME, NPY_TIMEDELTA, - NPY_OBJECT=19, + NPY_OBJECT=20, NPY_STRING, NPY_UNICODE, NPY_VOID, NPY_NTYPES, @@ -88,6 +88,7 @@ enum NPY_TYPES { NPY_BOOL=0, /* default scalar priority */ #define NPY_SCALAR_PRIORITY -1000000.0 +/*TODO HALF - This is used as how many complex floating point types in the code */ /* How many floating point types are there */ #define NPY_NUM_FLOATTYPE 3 @@ -115,6 +116,7 @@ enum NPY_TYPECHAR { NPY_BOOLLTR = '?', NPY_ULONGLTR = 'L', NPY_LONGLONGLTR = 'q', NPY_ULONGLONGLTR = 'Q', + NPY_HALFLTR = 'e', NPY_FLOATLTR = 'f', NPY_DOUBLELTR = 'd', NPY_LONGDOUBLELTR = 'g', @@ -1230,7 +1232,7 @@ PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter); #define PyTypeNum_ISINTEGER(type) (((type) >= NPY_BYTE) && \ ((type) <= NPY_ULONGLONG)) -#define PyTypeNum_ISFLOAT(type) (((type) >= NPY_FLOAT) && \ +#define PyTypeNum_ISFLOAT(type) (((type) >= NPY_HALF) && \ ((type) <= NPY_LONGDOUBLE)) #define PyTypeNum_ISNUMBER(type) ((type) <= NPY_CLONGDOUBLE) diff --git a/numpy/core/include/numpy/noprefix.h b/numpy/core/include/numpy/noprefix.h index d4ccfc4a3..571c9d082 100644 --- a/numpy/core/include/numpy/noprefix.h +++ b/numpy/core/include/numpy/noprefix.h @@ -108,12 +108,14 @@ compatibility measure*/ #define SIZEOF_LONGDOUBLE NPY_SIZEOF_LONGDOUBLE #define SIZEOF_LONGLONG NPY_SIZEOF_LONGLONG +#define SIZEOF_HALF NPY_SIZEOF_HALF #define BITSOF_BOOL NPY_BITSOF_BOOL #define BITSOF_CHAR NPY_BITSOF_CHAR #define BITSOF_SHORT NPY_BITSOF_SHORT #define BITSOF_INT NPY_BITSOF_INT #define BITSOF_LONG NPY_BITSOF_LONG #define BITSOF_LONGLONG NPY_BITSOF_LONGLONG +#define BITSOF_HALF NPY_BITSOF_HALF #define BITSOF_FLOAT NPY_BITSOF_FLOAT #define BITSOF_DOUBLE NPY_BITSOF_DOUBLE #define BITSOF_LONGDOUBLE NPY_BITSOF_LONGDOUBLE diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h index 474f1c3af..998cfdaef 100644 --- a/numpy/core/include/numpy/npy_common.h +++ b/numpy/core/include/numpy/npy_common.h @@ -31,9 +31,11 @@ enum { #define NPY_UINT_FMT "u" #define NPY_LONG_FMT "ld" #define NPY_ULONG_FMT "lu" +#define NPY_HALF_FMT "g" #define NPY_FLOAT_FMT "g" #define NPY_DOUBLE_FMT "g" + #ifdef PY_LONG_LONG typedef PY_LONG_LONG npy_longlong; typedef unsigned PY_LONG_LONG npy_ulonglong; @@ -195,6 +197,7 @@ typedef struct { npy_longdouble real, imag; } npy_clongdouble; #define NPY_MIN_LONG LONG_MIN #define NPY_MAX_ULONG ULONG_MAX +#define NPY_SIZEOF_HALF 2 #define NPY_SIZEOF_DATETIME 8 #define NPY_SIZEOF_TIMEDELTA 8 @@ -204,6 +207,7 @@ typedef struct { npy_longdouble real, imag; } npy_clongdouble; #define NPY_BITSOF_INT (NPY_SIZEOF_INT * CHAR_BIT) #define NPY_BITSOF_LONG (NPY_SIZEOF_LONG * CHAR_BIT) #define NPY_BITSOF_LONGLONG (NPY_SIZEOF_LONGLONG * CHAR_BIT) +#define NPY_BITSOF_HALF (NPY_SIZEOF_HALF * CHAR_BIT) #define NPY_BITSOF_FLOAT (NPY_SIZEOF_FLOAT * CHAR_BIT) #define NPY_BITSOF_DOUBLE (NPY_SIZEOF_DOUBLE * CHAR_BIT) #define NPY_BITSOF_LONGDOUBLE (NPY_SIZEOF_LONGDOUBLE * CHAR_BIT) @@ -582,20 +586,7 @@ typedef struct { npy_longdouble real, imag; } npy_clongdouble; -#if NPY_BITSOF_DOUBLE == 16 -#ifndef NPY_FLOAT16 -#define NPY_FLOAT16 NPY_DOUBLE -#define NPY_COMPLEX32 NPY_CDOUBLE - typedef double npy_float16; - typedef npy_cdouble npy_complex32; -# define PyFloat16ScalarObject PyDoubleScalarObject -# define PyComplex32ScalarObject PyCDoubleScalarObject -# define PyFloat16ArrType_Type PyDoubleArrType_Type -# define PyComplex32ArrType_Type PyCDoubleArrType_Type -#define NPY_FLOAT16_FMT NPY_DOUBLE_FMT -#define NPY_COMPLEX32_FMT NPY_CDOUBLE_FMT -#endif -#elif NPY_BITSOF_DOUBLE == 32 +#if NPY_BITSOF_DOUBLE == 32 #ifndef NPY_FLOAT32 #define NPY_FLOAT32 NPY_DOUBLE #define NPY_COMPLEX64 NPY_CDOUBLE @@ -664,20 +655,7 @@ typedef struct { npy_longdouble real, imag; } npy_clongdouble; -#if NPY_BITSOF_FLOAT == 16 -#ifndef NPY_FLOAT16 -#define NPY_FLOAT16 NPY_FLOAT -#define NPY_COMPLEX32 NPY_CFLOAT - typedef float npy_float16; - typedef npy_cfloat npy_complex32; -# define PyFloat16ScalarObject PyFloatScalarObject -# define PyComplex32ScalarObject PyCFloatScalarObject -# define PyFloat16ArrType_Type PyFloatArrType_Type -# define PyComplex32ArrType_Type PyCFloatArrType_Type -#define NPY_FLOAT16_FMT NPY_FLOAT_FMT -#define NPY_COMPLEX32_FMT NPY_CFLOAT_FMT -#endif -#elif NPY_BITSOF_FLOAT == 32 +#if NPY_BITSOF_FLOAT == 32 #ifndef NPY_FLOAT32 #define NPY_FLOAT32 NPY_FLOAT #define NPY_COMPLEX64 NPY_CFLOAT @@ -744,21 +722,12 @@ typedef struct { npy_longdouble real, imag; } npy_clongdouble; #endif #endif +/* half/float16 isn't a floating-point type in C */ +#define NPY_FLOAT16 NPY_HALF +typedef npy_uint16 npy_half; +typedef npy_half npy_float16; -#if NPY_BITSOF_LONGDOUBLE == 16 -#ifndef NPY_FLOAT16 -#define NPY_FLOAT16 NPY_LONGDOUBLE -#define NPY_COMPLEX32 NPY_CLONGDOUBLE - typedef npy_longdouble npy_float16; - typedef npy_clongdouble npy_complex32; -# define PyFloat16ScalarObject PyLongDoubleScalarObject -# define PyComplex32ScalarObject PyCLongDoubleScalarObject -# define PyFloat16ArrType_Type PyLongDoubleArrType_Type -# define PyComplex32ArrType_Type PyCLongDoubleArrType_Type -#define NPY_FLOAT16_FMT NPY_LONGDOUBLE_FMT -#define NPY_COMPLEX32_FMT NPY_CLONGDOUBLE_FMT -#endif -#elif NPY_BITSOF_LONGDOUBLE == 32 +#if NPY_BITSOF_LONGDOUBLE == 32 #ifndef NPY_FLOAT32 #define NPY_FLOAT32 NPY_LONGDOUBLE #define NPY_COMPLEX64 NPY_CLONGDOUBLE diff --git a/numpy/core/include/numpy/old_defines.h b/numpy/core/include/numpy/old_defines.h index a9dfd5c21..8c83a70a2 100644 --- a/numpy/core/include/numpy/old_defines.h +++ b/numpy/core/include/numpy/old_defines.h @@ -23,6 +23,7 @@ #define PyArray_ULONG NPY_ULONG #define PyArray_LONGLONG NPY_LONGLONG #define PyArray_ULONGLONG NPY_ULONGLONG +#define PyArray_HALF NPY_HALF #define PyArray_FLOAT NPY_FLOAT #define PyArray_DOUBLE NPY_DOUBLE #define PyArray_LONGDOUBLE NPY_LONGDOUBLE @@ -99,6 +100,7 @@ #define PyArray_ULONGLTR NPY_ULONGLTR #define PyArray_LONGLONGLTR NPY_LONGLONGLTR #define PyArray_ULONGLONGLTR NPY_ULONGLONGLTR +#define PyArray_HALFLTR NPY_HALFLTR #define PyArray_FLOATLTR NPY_FLOATLTR #define PyArray_DOUBLELTR NPY_DOUBLELTR #define PyArray_LONGDOUBLELTR NPY_LONGDOUBLELTR diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h index b795b5418..35d173cda 100644 --- a/numpy/core/include/numpy/ufuncobject.h +++ b/numpy/core/include/numpy/ufuncobject.h @@ -324,6 +324,8 @@ typedef struct _loop1d_info { #define generate_divbyzero_error() feraiseexcept(FE_DIVBYZERO) #define generate_overflow_error() feraiseexcept(FE_OVERFLOW) +#define generate_underflow_error() feraiseexcept(FE_UNDERFLOW) +#define generate_invalid_error() feraiseexcept(FE_INVALID) #elif defined(_AIX) @@ -343,6 +345,8 @@ typedef struct _loop1d_info { #define generate_divbyzero_error() fp_raise_xcp(FP_DIV_BY_ZERO) #define generate_overflow_error() fp_raise_xcp(FP_OVERFLOW) +#define generate_underflow_error() fp_raise_xcp(FP_UNDERFLOW) +#define generate_invalid_error() fp_raise_xcp(FP_INVALID) #else @@ -385,6 +389,32 @@ static void generate_overflow_error(void) { } #endif +#if !defined(generate_underflow_error) +static double numeric_small = 1e-300; +static void generate_underflow_error(void) { + double dummy; + dummy = numeric_small * 1e-300; + if (!dummy) + return; + else + numeric_small += 1e-300; + return; +} +#endif + +#if !defined(generate_invalid_error) +static double numeric_inv_inf = NPY_INF; +static void generate_invalid_error(void) { + double dummy; + dummy = numeric_inv_inf - NPY_INF; + if (!dummy) + return; + else + numeric_inv_inf += 1.0; + return; +} +#endif + /* Make sure it gets defined if it isn't already */ #ifndef UFUNC_NOFPE #define UFUNC_NOFPE diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py index 74b44fdab..4f16d2e3a 100644 --- a/numpy/core/numerictypes.py +++ b/numpy/core/numerictypes.py @@ -65,6 +65,7 @@ Exported symbols include: | ulonglong +-> inexact | +-> floating (floatxx) (kind=f) + | | half | | single | | float_ (double) | | longfloat @@ -828,12 +829,12 @@ del key typecodes = {'Character':'c', 'Integer':'bhilqp', 'UnsignedInteger':'BHILQP', - 'Float':'fdg', + 'Float':'efdg', 'Complex':'FDG', 'AllInteger':'bBhHiIlLqQpP', - 'AllFloat':'fdgFDG', + 'AllFloat':'efdgFDG', 'Datetime': 'Mm', - 'All':'?bhilqpBHILQPfdgFDGSUVOMm'} + 'All':'?bhilqpBHILQPefdgFDGSUVOMm'} # backwards compatibility --- deprecated name typeDict = sctypeDict diff --git a/numpy/core/setup.py b/numpy/core/setup.py index f71ec108a..b854e879f 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -610,6 +610,8 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import get_cmd subpath = join('src', 'umath') + # NOTE: For manual template conversion of loops.h.src, read the note + # in that file. sources = [join(local_dir, subpath, 'loops.c.src'), join(local_dir, subpath, 'umathmodule.c.src')] @@ -660,7 +662,7 @@ def configuration(parent_package='',top_path=None): generate_numpyconfig_h, generate_numpy_api, ], - ) + libraries=['npymath']) # npymath needs the config.h and numpyconfig.h files to be generated, but # build_clib cannot handle generate_config_h and generate_numpyconfig_h @@ -692,6 +694,7 @@ def configuration(parent_package='',top_path=None): sources=[join('src', 'npymath', 'npy_math.c.src'), join('src', 'npymath', 'ieee754.c.src'), join('src', 'npymath', 'npy_math_complex.c.src'), + join('src', 'npymath', 'halffloat.c'), get_mathlib_info], install_dir='lib') config.add_npy_pkg_config("npymath.ini.in", "lib/npy-pkg-config", @@ -802,6 +805,7 @@ def configuration(parent_package='',top_path=None): generate_numpyconfig_h, generate_numpy_api, generate_ufunc_api], + libraries=['npymath'], ) # Configure blasdot diff --git a/numpy/core/src/_sortmodule.c.src b/numpy/core/src/_sortmodule.c.src index 709a26a1c..527d0c402 100644 --- a/numpy/core/src/_sortmodule.c.src +++ b/numpy/core/src/_sortmodule.c.src @@ -30,6 +30,7 @@ #include "Python.h" #include "numpy/noprefix.h" #include "numpy/npy_math.h" +#include "numpy/halffloat.h" #include "npy_config.h" @@ -48,12 +49,12 @@ /**begin repeat * * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, * CDOUBLE,CLONGDOUBLE, INTP# * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, - * npy_float, npy_double, npy_longdouble, npy_cfloat, npy_cdouble, - * npy_clongdouble, npy_intp# + * npy_half, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble, npy_intp# */ #define @TYPE@_SWAP(a,b) {@type@ tmp = (b); (b)=(a); (a) = tmp;} @@ -92,6 +93,19 @@ NPY_INLINE static int } /**end repeat**/ +NPY_INLINE static int +HALF_LT(npy_half a, npy_half b) +{ + int ret; + + if (npy_half_isnan(b)) { + ret = !npy_half_isnan(a); + } else { + ret = !npy_half_isnan(a) && npy_half_lt_nonan(a, b); + } + + return ret; +} /* * For inline functions SUN recommends not using a return in the then part @@ -217,10 +231,10 @@ UNICODE_LT(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) /**begin repeat * * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, ushort, float, double, longdouble, * cfloat, cdouble, clongdouble# */ @@ -965,7 +979,7 @@ add_sortfuncs(void) /**begin repeat * * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, STRING, UNICODE# */ descr = PyArray_DescrFromType(PyArray_@TYPE@); diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index fb48704ba..c9d517c50 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -12,6 +12,7 @@ #include "numpy/npy_3kcompat.h" #include "numpy/npy_math.h" +#include "numpy/halffloat.h" #include "common.h" #include "ctors.h" @@ -21,6 +22,7 @@ #include "numpyos.h" + /* ***************************************************************************** ** PYTHON TYPES TO C TYPES ** @@ -45,6 +47,18 @@ MyPyFloat_AsDouble(PyObject *obj) return ret; } +static npy_half +MyPyFloat_AsHalf(PyObject *obj) +{ + return npy_double_to_half(MyPyFloat_AsDouble(obj)); +} + +static PyObject * +MyPyFloat_FromHalf(npy_half h) +{ + return PyFloat_FromDouble(npy_half_to_double(h)); +} + /**begin repeat * #type = long, longlong# @@ -97,18 +111,18 @@ static char * _SEQUENCE_MESSAGE = "error setting an array element with a sequenc /**begin repeat * * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, LONG, UINT, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE# + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE# * #func1 = PyBool_FromLong, PyInt_FromLong*6, PyLong_FromUnsignedLong*2, * PyLong_FromLongLong, PyLong_FromUnsignedLongLong, - * PyFloat_FromDouble*2# + * MyPyFloat_FromHalf, PyFloat_FromDouble*2# * #func2 = PyObject_IsTrue, MyPyLong_AsLong*6, MyPyLong_AsUnsignedLong*2, * MyPyLong_AsLongLong, MyPyLong_AsUnsignedLongLong, - * MyPyFloat_AsDouble*2# + * MyPyFloat_AsHalf, MyPyFloat_AsDouble*2# * #type = Bool, byte, ubyte, short, ushort, int, long, uint, ulong, - * longlong, ulonglong, float, double# - * #type1 = long*7, ulong*2, longlong, ulonglong, float, double# + * longlong, ulonglong, npy_half, float, double# + * #type1 = long*7, ulong*2, longlong, ulonglong, npy_half, float, double# * #kind = Bool, Byte, UByte, Short, UShort, Int, Long, UInt, ULong, - * LongLong, ULongLong, Float, Double# + * LongLong, ULongLong, Half, Float, Double# */ static PyObject * @TYPE@_getitem(char *ip, PyArrayObject *ap) { @@ -1236,7 +1250,7 @@ TIMEDELTA_setitem(PyObject *op, char *ov, PyArrayObject *ap) { * #totype = byte, ubyte, short, ushort, int, uint, long, ulong, * longlong, ulonglong, float, double, longdouble, datetime, * timedelta# -*/ + */ /**begin repeat1 * @@ -1278,6 +1292,97 @@ static void /**begin repeat * + * #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, LONGDOUBLE, DATETIME, + * TIMEDELTA# + * #type = byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, longdouble, datetime, + * timedelta# + */ + +static void +@TYPE@_to_HALF(@type@ *ip, npy_half *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = npy_float_to_half((float)(*ip++)); + } +} + +static void +HALF_to_@TYPE@(npy_half *ip, @type@ *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = (@type@)npy_half_to_float(*ip++); + } +} + +/**end repeat**/ +#if SIZEOF_SHORT == 2 +#define HALF_to_HALF SHORT_to_SHORT +#elif SIZEOF_INT == 2 +#define HALF_to_HALF INT_to_INT +#endif + +/**begin repeat + * + * #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + * #type = float, double, float, double# + * #itype = npy_uint32, npy_uint64, npy_uint32, npy_uint64# + * #iscomplex = 0, 0, 1, 1# + */ + +static void +@TYPE@_to_HALF(@itype@ *ip, npy_half *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = npy_@type@bits_to_halfbits(*ip); +#if @iscomplex@ + ip += 2; +#else + ip++; +#endif + } +} + +static void +HALF_to_@TYPE@(npy_half *ip, @itype@ *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = npy_halfbits_to_@type@bits(*ip++); +#if @iscomplex@ + *op++ = 0; +#endif + } +} + +/**end repeat**/ + +static void +CLONGDOUBLE_to_HALF(longdouble *ip, npy_half *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = npy_double_to_half((double) (*ip++)); + ip += 2; + } +} + +static void +HALF_to_CLONGDOUBLE(npy_half *ip, longdouble *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = npy_half_to_double(*ip++); + *op++ = 0; + } +} + +/**begin repeat + * * #FROMTYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME, * TIMEDELTA# @@ -1295,6 +1400,15 @@ static void } /**end repeat**/ +static void +HALF_to_BOOL(npy_half *ip, Bool *op, intp n, + PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) +{ + while (n--) { + *op++ = (Bool)(!npy_half_iszero(*ip++)); + } +} + /**begin repeat * * #FROMTYPE = CFLOAT, CDOUBLE, CLONGDOUBLE# @@ -1314,18 +1428,20 @@ static void /**begin repeat * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, DATETIME, * TIMEDELTA# * #totype = byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, datetime, + * longlong, ulonglong, npy_half, float, double, longdouble, datetime, * timedelta# -*/ + * #one = 1*10, NPY_HALF_ONE, 1*5# + * #zero = 0*10, NPY_HALF_ZERO, 0*5# + */ static void BOOL_to_@TOTYPE@(Bool *ip, @totype@ *op, intp n, PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop)) { while (n--) { - *op++ = (@totype@)(*ip++ != FALSE); + *op++ = (@totype@)((*ip++ != FALSE) ? @one@ : @zero@); } } /**end repeat**/ @@ -1383,14 +1499,14 @@ static void /**begin repeat * * #FROMTYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, STRING, UNICODE, VOID, OBJECT, * DATETIME, TIMEDELTA# * #fromtype = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * cfloat, cdouble, clongdouble, char, char, char, PyObject *, * datetime, timedelta# - * #skip = 1*17, aip->descr->elsize*3, 1*3# + * #skip = 1*18, aip->descr->elsize*3, 1*3# */ static void @FROMTYPE@_to_OBJECT(@fromtype@ *ip, PyObject **op, intp n, PyArrayObject *aip, @@ -1431,14 +1547,14 @@ static void /**begin repeat * * #TOTYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, STRING, UNICODE, VOID, DATETIME, * TIMEDELTA# * #totype = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * cfloat, cdouble, clongdouble, char, char, char, datetime, * timedelta# - * #skip = 1*17, aop->descr->elsize*3, 1*2# + * #skip = 1*18, aop->descr->elsize*3, 1*2# */ static void OBJECT_to_@TOTYPE@(PyObject **ip, @totype@ *op, intp n, @@ -1461,13 +1577,13 @@ OBJECT_to_@TOTYPE@(PyObject **ip, @totype@ *op, intp n, /**begin repeat * - * #from = STRING*22, UNICODE*22, VOID*22# - * #fromtyp = char*66# - * #to = (BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE, STRING, UNICODE, VOID, DATETIME, TIMEDELTA)*3# - * #totyp = (Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble, char, char, char, datetime, timedelta)*3# - * #oskip = (1*17,aop->descr->elsize*3,1*2)*3# - * #convert = 1*17, 0*3, 1*2, 1*17, 0*3, 1*2, 0*22# - * #convstr = (Int*9, Long*2, Float*3, Complex*3, Tuple*3, Long*2)*3# + * #from = STRING*23, UNICODE*23, VOID*23# + * #fromtyp = char*69# + * #to = (BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE, STRING, UNICODE, VOID, DATETIME, TIMEDELTA)*3# + * #totyp = (Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, npy_half, float, double, longdouble, cfloat, cdouble, clongdouble, char, char, char, datetime, timedelta)*3# + * #oskip = (1*18,aop->descr->elsize*3,1*2)*3# + * #convert = 1*18, 0*3, 1*2, 1*18, 0*3, 1*2, 0*23# + * #convstr = (Int*9, Long*2, Float*4, Complex*3, Tuple*3, Long*2)*3# */ static void @from@_to_@to@(@fromtyp@ *ip, @totyp@ *op, intp n, PyArrayObject *aip, @@ -1484,23 +1600,23 @@ static void return; } /* convert from Python object to needed one */ - if (@convert@) { - PyObject *new, *args; - /* call out to the Python builtin given by convstr */ - args = Py_BuildValue("(N)", temp); +#if @convert@ + PyObject *new, *args; + /* call out to the Python builtin given by convstr */ + args = Py_BuildValue("(N)", temp); #if defined(NPY_PY3K) #define PyInt_Type PyLong_Type #endif - new = Py@convstr@_Type.tp_new(&Py@convstr@_Type, args, NULL); + new = Py@convstr@_Type.tp_new(&Py@convstr@_Type, args, NULL); #if defined(NPY_PY3K) #undef PyInt_Type #endif - Py_DECREF(args); - temp = new; - if (temp == NULL) { - return; - } + Py_DECREF(args); + temp = new; + if (temp == NULL) { + return; } +#endif /* @convert@ */ if (@to@_setitem(temp,(char *)op, aop)) { Py_DECREF(temp); return; @@ -1513,13 +1629,13 @@ static void /**begin repeat * - * #to = STRING*19, UNICODE*19, VOID*19# - * #totyp = char*19, char*19, char*19# + * #to = STRING*20, UNICODE*20, VOID*20# + * #totyp = char*20, char*20, char*20# * #from = (BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA)*3# * #fromtyp = (Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * cfloat, cdouble, clongdouble, datetime, timedelta)*3# */ static void @@ -1587,6 +1703,17 @@ static int } /**end repeat**/ +static int +HALF_scan(FILE *fp, npy_half *ip, void *NPY_UNUSED(ignore), PyArray_Descr *NPY_UNUSED(ignored)) +{ + double result; + int ret; + + ret = NumPyOS_ascii_ftolf(fp, &result); + *ip = npy_double_to_half(result); + return ret; +} + /**begin repeat * #fname = BYTE, UBYTE# * #type = byte, ubyte# @@ -1666,6 +1793,15 @@ static int } /**end repeat**/ +static int +HALF_fromstr(char *str, npy_half *ip, char **endptr, PyArray_Descr *NPY_UNUSED(ignore)) +{ + double result; + + result = NumPyOS_ascii_strtod(str, endptr); + *ip = npy_double_to_half(result); + return 0; +} /**begin repeat @@ -1684,11 +1820,11 @@ static int /**begin repeat * - * #fname = SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, + * #fname = SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, HALF, FLOAT, * DOUBLE, LONGDOUBLE, DATETIME, TIMEDELTA# - * #fsize = SHORT, SHORT, INT, INT, LONG, LONG, LONGLONG, LONGLONG, FLOAT, + * #fsize = SHORT, SHORT, INT, INT, LONG, LONG, LONGLONG, LONGLONG, HALF, FLOAT, * DOUBLE, LONGDOUBLE, DATETIME, TIMEDELTA# - * #type = short, ushort, int, uint, long, ulong, longlong, ulonglong, float, + * #type = short, ushort, int, uint, long, ulong, longlong, ulonglong, npy_half, float, * double, longdouble, datetime, timedelta# */ static void @@ -2223,22 +2359,25 @@ UNICODE_copyswap (char *dst, char *src, int swap, PyArrayObject *arr) ***************************************************************************** */ +#define _NONZERO(a) ((a) != 0) + /**begin repeat * * #fname = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * DATETIME, TIMEDELTA# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * datetime, timedelta# - * #isfloat = 0*11, 1*3, 0*2# + * #isfloat = 0*11, 1*4, 0*2# + * #nonzero = _NONZERO*11, !npy_half_iszero, _NONZERO*5# */ static Bool @fname@_nonzero (char *ip, PyArrayObject *ap) { if (ap == NULL || PyArray_ISBEHAVED_RO(ap)) { @type@ *ptmp = (@type@ *)ip; - return (Bool) (*ptmp != 0); + return (Bool) @nonzero@(*ptmp); } else { /* @@ -2252,7 +2391,7 @@ static Bool #else memcpy(&tmp, ip, sizeof(@type@)); #endif - return (Bool) (tmp != 0); + return (Bool) @nonzero@(tmp); } } /**end repeat**/ @@ -2562,6 +2701,31 @@ C@TYPE@_compare(@type@ *pa, @type@ *pb) /**end repeat**/ +static int +HALF_compare (npy_half *pa, npy_half *pb, PyArrayObject *NPY_UNUSED(ap)) +{ + npy_half a = *pa, b = *pb; + Bool a_isnan, b_isnan; + int ret; + + a_isnan = npy_half_isnan(a); + b_isnan = npy_half_isnan(b); + + if (a_isnan) { + ret = b_isnan ? 0 : -1; + } else if (b_isnan) { + ret = 1; + } else if(npy_half_lt_nonan(a, b)) { + ret = -1; + } else if(npy_half_lt_nonan(b, a)) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + /* object type */ @@ -2728,18 +2892,21 @@ finish: ***************************************************************************** */ +#define _LESS_THAN_OR_EQUAL(a,b) ((a) <= (b)) /**begin repeat * * #fname = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * float, double, longdouble, datetime, timedelta# - * #isfloat = 0*11, 1*6, 0*2# - * #iscomplex = 0*14, 1*3, 0*2# - * #incr = ip++*14, ip+=2*3, ip++*2# + * #isfloat = 0*11, 1*7, 0*2# + * #isnan = nop*11, npy_half_isnan, npy_isnan*6, nop*2# + * #le = _LESS_THAN_OR_EQUAL*11, npy_half_le, _LESS_THAN_OR_EQUAL*8# + * #iscomplex = 0*15, 1*3, 0*2# + * #incr = ip++*15, ip+=2*3, ip++*2# */ static int @fname@_argmax(@type@ *ip, intp n, intp *max_ind, PyArrayObject *NPY_UNUSED(aip)) @@ -2753,13 +2920,13 @@ static int *max_ind = 0; #if @isfloat@ - if (npy_isnan(mp)) { + if (@isnan@(mp)) { /* nan encountered; it's maximal */ return 0; } #endif #if @iscomplex@ - if (npy_isnan(mp_im)) { + if (@isnan@(mp_im)) { /* nan encountered; it's maximal */ return 0; } @@ -2773,21 +2940,21 @@ static int #if @iscomplex@ /* Lexical order for complex numbers */ if ((ip[0] > mp) || ((ip[0] == mp) && (ip[1] > mp_im)) - || npy_isnan(ip[0]) || npy_isnan(ip[1])) { + || @isnan@(ip[0]) || @isnan@(ip[1])) { mp = ip[0]; mp_im = ip[1]; *max_ind = i; - if (npy_isnan(mp) || npy_isnan(mp_im)) { + if (@isnan@(mp) || @isnan@(mp_im)) { /* nan encountered, it's maximal */ break; } } #else - if (!(*ip <= mp)) { /* negated, for correct nan handling */ + if (!@le@(*ip, mp)) { /* negated, for correct nan handling */ mp = *ip; *max_ind = i; #if @isfloat@ - if (npy_isnan(mp)) { + if (@isnan@(mp)) { /* nan encountered, it's maximal */ break; } @@ -2800,6 +2967,8 @@ static int /**end repeat**/ +#undef _LESS_THAN_OR_EQUAL + static int OBJECT_argmax(PyObject **ip, intp n, intp *max_ind, PyArrayObject *NPY_UNUSED(aip)) { @@ -2910,6 +3079,19 @@ static void } /**end repeat**/ +static void +HALF_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n, + void *NPY_UNUSED(ignore)) +{ + float tmp = 0.0f; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + tmp += npy_half_to_float(*((npy_half *)ip1)) * + npy_half_to_float(*((npy_half *)ip2)); + } + *((npy_half *)op) = npy_float_to_half(tmp); +} /**begin repeat * @@ -3041,6 +3223,19 @@ static void } /**end repeat**/ +static void +HALF_fill(npy_half *buffer, npy_intp length, void *NPY_UNUSED(ignored)) +{ + npy_intp i; + float start = npy_half_to_float(buffer[0]); + float delta = npy_half_to_float(buffer[1]); + + delta -= start; + for (i = 2; i < length; ++i) { + buffer[i] = npy_float_to_half(start + i*delta); + } +} + /**begin repeat * * #NAME = CFLOAT, CDOUBLE, CLONGDOUBLE# @@ -3095,10 +3290,10 @@ static void /**begin repeat * * #NAME = SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, - * FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE, * DATETIME, TIMEDELTA# * #typ = short, ushort, int, uint, long, ulong, longlong, ulonglong, - * float, double, longdouble, cfloat, cdouble, clongdouble, + * npy_half, float, double, longdouble, cfloat, cdouble, clongdouble, * datetime, timedelta# */ static void @@ -3120,15 +3315,27 @@ static void ***************************************************************************** */ +#define _LESS_THAN(a, b) ((a) < (b)) +#define _GREATER_THAN(a, b) ((a) > (b)) +/* + * In fastclip, 'b' was already checked for NaN, so the half comparison + * only needs to check 'a' for NaN. + */ +#define _HALF_LESS_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(a, b)) +#define _HALF_GREATER_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(b, a)) /**begin repeat * * #name = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * DATETIME, TIMEDELTA# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * datetime, timedelta# + * #isfloat = 0*11, 1*4, 0*2# + * #isnan = nop*11, npy_half_isnan, npy_isnan*3, nop*2# + * #lt = _LESS_THAN*11, _HALF_LESS_THAN, _LESS_THAN*5# + * #gt = _GREATER_THAN*11, _HALF_GREATER_THAN, _GREATER_THAN*5# */ static void @name@_fastclip(@type@ *in, intp ni, @type@ *min, @type@ *max, @type@ *out) @@ -3138,30 +3345,47 @@ static void if (max != NULL) { max_val = *max; +#if @isfloat@ + /* NaNs result in no clipping, so optimize the case away */ + if (@isnan@(max_val)) { + if (min == NULL) { + return; + } + max = NULL; + } +#endif } if (min != NULL) { min_val = *min; +#if @isfloat@ + if (@isnan@(min_val)) { + if (max == NULL) { + return; + } + min = NULL; + } +#endif } if (max == NULL) { for (i = 0; i < ni; i++) { - if (in[i] < min_val) { + if (@lt@(in[i], min_val)) { out[i] = min_val; } } } else if (min == NULL) { for (i = 0; i < ni; i++) { - if (in[i] > max_val) { + if (@gt@(in[i], max_val)) { out[i] = max_val; } } } else { for (i = 0; i < ni; i++) { - if (in[i] < min_val) { + if (@lt@(in[i], min_val)) { out[i] = min_val; } - else if (in[i] > max_val) { + else if (@gt@(in[i], max_val)) { out[i] = max_val; } } @@ -3169,6 +3393,11 @@ static void } /**end repeat**/ +#undef _LESS_THAN +#undef _GREATER_THAN +#undef _HALF_LESS_THAN +#undef _HALF_GREATER_THAN + /**begin repeat * * #name = CFLOAT, CDOUBLE, CLONGDOUBLE# @@ -3229,10 +3458,10 @@ static void /**begin repeat * * #name = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * cfloat, cdouble, clongdouble, datetime, timedelta# */ static void @@ -3273,10 +3502,10 @@ static void /**begin repeat * * #name = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# * #type = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * cfloat, cdouble, clongdouble, datetime, timedelta# */ static int @@ -3431,6 +3660,7 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { (PyArray_VectorUnaryFunc*)@from@_to_ULONG, (PyArray_VectorUnaryFunc*)@from@_to_LONGLONG, (PyArray_VectorUnaryFunc*)@from@_to_ULONGLONG, + (PyArray_VectorUnaryFunc*)@from@_to_HALF, (PyArray_VectorUnaryFunc*)@from@_to_FLOAT, (PyArray_VectorUnaryFunc*)@from@_to_DOUBLE, (PyArray_VectorUnaryFunc*)@from@_to_LONGDOUBLE, @@ -3469,24 +3699,23 @@ static PyArray_Descr @from@_Descr = { /**end repeat**/ - /**begin repeat * * #from = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, OBJECT, DATETIME, TIMEDELTA# - * #num = 1*14, 2*3, 1*3# + * #num = 1*15, 2*3, 1*3# * #fromtyp = Bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, longdouble, + * longlong, ulonglong, npy_half, float, double, longdouble, * float, double, longdouble, PyObject *, datetime, timedelta# * #NAME = Bool, Byte, UByte, Short, UShort, Int, UInt, Long, ULong, - * LongLong, ULongLong, Float, Double, LongDouble, + * LongLong, ULongLong, Half, Float, Double, LongDouble, * CFloat, CDouble, CLongDouble, Object, Datetime, Timedelta# * #kind = GENBOOL, SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, - * SIGNED, UNSIGNED, FLOATING, FLOATING, FLOATING, + * SIGNED, UNSIGNED, FLOATING, FLOATING, FLOATING, FLOATING, * COMPLEX, COMPLEX, COMPLEX, OBJECT, DATETIME, TIMEDELTA# - * #endian = |*3, =*14, |, =*2# - * #isobject= 0*17,NPY_OBJECT_DTYPE_FLAGS,0*2# + * #endian = |*3, =*15, |, =*2# + * #isobject= 0*18,NPY_OBJECT_DTYPE_FLAGS,0*2# */ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { (PyArray_GetItemFunc*)@from@_getitem, @@ -3527,6 +3756,7 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { (PyArray_VectorUnaryFunc*)@from@_to_ULONG, (PyArray_VectorUnaryFunc*)@from@_to_LONGLONG, (PyArray_VectorUnaryFunc*)@from@_to_ULONGLONG, + (PyArray_VectorUnaryFunc*)@from@_to_HALF, (PyArray_VectorUnaryFunc*)@from@_to_FLOAT, (PyArray_VectorUnaryFunc*)@from@_to_DOUBLE, (PyArray_VectorUnaryFunc*)@from@_to_LONGDOUBLE, @@ -3603,6 +3833,7 @@ static PyArray_Descr *_builtin_descrs[] = { &ULONG_Descr, &LONGLONG_Descr, &ULONGLONG_Descr, + &HALF_Descr, &FLOAT_Descr, &DOUBLE_Descr, &LONGDOUBLE_Descr, @@ -3699,7 +3930,7 @@ set_typeinfo(PyObject *dict) /**begin repeat * * #name = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, INTP, UINTP, - * LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONG, ULONG, LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, OBJECT, STRING, UNICODE, VOID, * DATETIME,TIMEDELTA# */ @@ -3709,7 +3940,7 @@ set_typeinfo(PyObject *dict) /**begin repeat * #name = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, - * LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONG, ULONG, LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, OBJECT, STRING, UNICODE, VOID, * DATETIME, TIMEDELTA# */ @@ -3766,9 +3997,9 @@ set_typeinfo(PyObject *dict) /**begin repeat * - * #type = float, double, longdouble, cfloat, cdouble, clongdouble# - * #name = FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE# - * #Name = Float, Double, LongDouble, CFloat, CDouble, CLongDouble# + * #type = npy_half, float, double, longdouble, cfloat, cdouble, clongdouble# + * #name = HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE# + * #Name = Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# */ PyDict_SetItemString(infodict, "@name@", #if defined(NPY_PY3K) diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index abc254058..4ad2e9f51 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -687,6 +687,9 @@ PyArray_TypestrConvert(int itemsize, int gentype) } else if (gentype == PyArray_FLOATINGLTR) { switch(itemsize) { + case 2: + newtype = PyArray_FLOAT16; + break; case 4: newtype = PyArray_FLOAT32; break; diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index d2aaf054f..0040e8ad5 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -567,7 +567,6 @@ PyArray_CanCastSafely(int fromtype, int totype) } } } - return 0; } diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index f35bfd662..d4dba719c 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -2946,6 +2946,7 @@ setup_scalartypes(PyObject *NPY_UNUSED(dict)) SINGLE_INHERIT(ULong, UnsignedInteger); SINGLE_INHERIT(ULongLong, UnsignedInteger); + SINGLE_INHERIT(Half, Floating); SINGLE_INHERIT(Float, Floating); DUAL_INHERIT(Double, Float, Floating); SINGLE_INHERIT(LongDouble, Floating); diff --git a/numpy/core/src/multiarray/scalarapi.c b/numpy/core/src/multiarray/scalarapi.c index f549ad35c..87e140c4e 100644 --- a/numpy/core/src/multiarray/scalarapi.c +++ b/numpy/core/src/multiarray/scalarapi.c @@ -57,6 +57,7 @@ scalar_value(PyObject *scalar, PyArray_Descr *descr) CASE(ULONG, ULong); CASE(LONGLONG, LongLong); CASE(ULONGLONG, ULongLong); + CASE(HALF, Half); CASE(FLOAT, Float); CASE(DOUBLE, Double); CASE(LONGDOUBLE, LongDouble); @@ -110,6 +111,7 @@ scalar_value(PyObject *scalar, PyArray_Descr *descr) else { /* Inexact */ if _CHK(Floating) { + _IFCASE(Half); _IFCASE(Float); _IFCASE(Double); _IFCASE(LongDouble); diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index b2e8690c7..c66337602 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -9,6 +9,7 @@ #define NPY_NO_PREFIX #include "numpy/arrayobject.h" #include "numpy/npy_math.h" +#include "numpy/halffloat.h" #include "numpy/arrayscalars.h" #include "numpy/npy_3kcompat.h" @@ -478,6 +479,12 @@ format_c@name@(char *buf, size_t buflen, c@name@ val, unsigned int prec) /**end repeat**/ +NPY_NO_EXPORT void +format_half(char *buf, size_t buflen, npy_half val, unsigned int prec) +{ + format_float(buf, buflen, npy_half_to_float(val), prec); +} + /* * over-ride repr and str of array-scalar strings and unicode to * remove NULL bytes and then call the corresponding functions @@ -516,7 +523,9 @@ static PyObject * } /**end repeat**/ -/* These values are finfo.precision + 2 */ +/* The REPR values are finfo.precision + 2 */ +#define HALFPREC_REPR 5 +#define HALFPREC_STR 5 #define FLOATPREC_REPR 8 #define FLOATPREC_STR 6 #define DOUBLEPREC_REPR 17 @@ -536,9 +545,10 @@ static PyObject * */ /**begin repeat - * #name = float, double, longdouble# - * #Name = Float, Double, LongDouble# - * #NAME = FLOAT, DOUBLE, LONGDOUBLE# + * #name = half, float, double, longdouble# + * #Name = Half, Float, Double, LongDouble# + * #NAME = HALF, FLOAT, DOUBLE, LONGDOUBLE# + * #hascomplex = 0, 1, 1, 1# */ /**begin repeat1 * #kind = str, repr# @@ -551,12 +561,13 @@ static PyObject * @name@type_@kind@(PyObject *self) { char buf[100]; - @name@ val = ((Py@Name@ScalarObject *)self)->obval; + npy_@name@ val = ((Py@Name@ScalarObject *)self)->obval; format_@name@(buf, sizeof(buf), val, PREC); return PyUString_FromString(buf); } +#if @hascomplex@ static PyObject * c@name@type_@kind@(PyObject *self) { @@ -566,6 +577,7 @@ c@name@type_@kind@(PyObject *self) format_c@name@(buf, sizeof(buf), val, PREC); return PyUString_FromString(buf); } +#endif #undef PREC @@ -576,16 +588,17 @@ c@name@type_@kind@(PyObject *self) * float type print (control print a, where a is a float type instance) */ /**begin repeat - * #name = float, double, longdouble# - * #Name = Float, Double, LongDouble# - * #NAME = FLOAT, DOUBLE, LONGDOUBLE# + * #name = half, float, double, longdouble# + * #Name = Half, Float, Double, LongDouble# + * #NAME = HALF, FLOAT, DOUBLE, LONGDOUBLE# + * #hascomplex = 0, 1, 1, 1# */ static int @name@type_print(PyObject *v, FILE *fp, int flags) { char buf[100]; - @name@ val = ((Py@Name@ScalarObject *)v)->obval; + npy_@name@ val = ((Py@Name@ScalarObject *)v)->obval; format_@name@(buf, sizeof(buf), val, (flags & Py_PRINT_RAW) ? @NAME@PREC_STR : @NAME@PREC_REPR); @@ -595,6 +608,7 @@ static int return 0; } +#if @hascomplex@ static int c@name@type_print(PyObject *v, FILE *fp, int flags) { @@ -609,6 +623,7 @@ c@name@type_print(PyObject *v, FILE *fp, int flags) Py_END_ALLOW_THREADS return 0; } +#endif /**end repeat**/ @@ -2117,13 +2132,13 @@ object_arrtype_dealloc(PyObject *v) /**begin repeat * #name = byte, short, int, long, longlong, ubyte, ushort, uint, ulong, - * ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble, - * string, unicode, object, datetime, timedelta# + * ulonglong, half, float, double, longdouble, cfloat, cdouble, + * clongdouble, string, unicode, object, datetime, timedelta# * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG, - * ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE, - * STRING, UNICODE, OBJECT, DATETIME, TIMEDELTA# - * #work = 0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,z,z,0,0,0# - * #default = 0*16,1*2,2,0*2# + * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, + * CLONGDOUBLE, STRING, UNICODE, OBJECT, DATETIME, TIMEDELTA# + * #work = 0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,z,z,0,0,0# + * #default = 0*17,1*2,2,0*2# */ #define _NPY_UNUSED2_1 @@ -2161,9 +2176,9 @@ static PyObject * */ if (obj == NULL) { #if @default@ == 0 - char *mem = malloc(sizeof(@name@)); + char *mem = malloc(sizeof(npy_@name@)); - memset(mem, 0, sizeof(@name@)); + memset(mem, 0, sizeof(npy_@name@)); robj = PyArray_Scalar(mem, typecode, NULL); free(mem); #elif @default@ == 1 @@ -2625,6 +2640,12 @@ c@lname@_arrtype_hash(PyObject *obj) /**end repeat**/ static long +half_arrtype_hash(PyObject *obj) +{ + return _Py_HashDouble(npy_half_to_double(((PyHalfScalarObject *)obj)->obval)); +} + +static long object_arrtype_hash(PyObject *obj) { return PyObject_Hash(((PyObjectScalarObject *)obj)->obval); @@ -3058,10 +3079,10 @@ NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { /**begin repeat * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, - * ULongLong, Float, Double, LongDouble, Datetime, Timedelta# - * #name = int*5, uint*5, float*3, datetime, timedelta# - * #CNAME = (CHAR, SHORT, INT, LONG, LONGLONG)*2, FLOAT, DOUBLE, LONGDOUBLE, - * DATETIME, TIMEDELTA# + * ULongLong, Half, Float, Double, LongDouble, Datetime, Timedelta# + * #name = int*5, uint*5, float*4, datetime, timedelta# + * #CNAME = (CHAR, SHORT, INT, LONG, LONGLONG)*2, HALF, FLOAT, DOUBLE, + * LONGDOUBLE, DATETIME, TIMEDELTA# */ #if BITSOF_@CNAME@ == 8 #define _THIS_SIZE "8" @@ -3276,10 +3297,10 @@ initialize_casting_tables(void) /* Compile-time loop of scalar kinds */ /**begin repeat * #NAME = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE# - * #SCKIND = BOOL, (INTNEG, INTPOS)*5, FLOAT, FLOAT, FLOAT, - * COMPLEX, COMPLEX, COMPLEX# + * #SCKIND = BOOL, (INTNEG, INTPOS)*5, FLOAT*4, + * COMPLEX*3# */ _npy_scalar_kinds_table[PyArray_@NAME@] = PyArray_@SCKIND@_SCALAR; /**end repeat**/ @@ -3309,22 +3330,22 @@ initialize_casting_tables(void) /* Compile-time loop of casting rules */ /**begin repeat * #FROM_NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE# * #FROM_BASENAME = BYTE, BYTE, SHORT, SHORT, INT, INT, LONG, LONG, - * LONGLONG, LONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * FLOAT, DOUBLE, LONGDOUBLE# * #from_isint = 1, 0, 1, 0, 1, 0, 1, 0, - * 1, 0, 0, 0, 0, + * 1, 0, 0, 0, 0, 0, * 0, 0, 0# * #from_isuint = 0, 1, 0, 1, 0, 1, 0, 1, - * 0, 1, 0, 0, 0, + * 0, 1, 0, 0, 0, 0, * 0, 0, 0# * #from_isfloat = 0, 0, 0, 0, 0, 0, 0, 0, - * 0, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 1, * 0, 0, 0# * #from_iscomplex = 0, 0, 0, 0, 0, 0, 0, 0, - * 0, 0, 0, 0, 0, + * 0, 0, 0, 0, 0, 0, * 1, 1, 1# */ #define _FROM_BSIZE NPY_SIZEOF_@FROM_BASENAME@ @@ -3335,22 +3356,22 @@ initialize_casting_tables(void) /**begin repeat1 * #TO_NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE# * #TO_BASENAME = BYTE, BYTE, SHORT, SHORT, INT, INT, LONG, LONG, - * LONGLONG, LONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * LONGLONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, * FLOAT, DOUBLE, LONGDOUBLE# * #to_isint = 1, 0, 1, 0, 1, 0, 1, 0, - * 1, 0, 0, 0, 0, + * 1, 0, 0, 0, 0, 0, * 0, 0, 0# * #to_isuint = 0, 1, 0, 1, 0, 1, 0, 1, - * 0, 1, 0, 0, 0, + * 0, 1, 0, 0, 0, 0, * 0, 0, 0# * #to_isfloat = 0, 0, 0, 0, 0, 0, 0, 0, - * 0, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 1, * 0, 0, 0# * #to_iscomplex = 0, 0, 0, 0, 0, 0, 0, 0, - * 0, 0, 0, 0, 0, + * 0, 0, 0, 0, 0, 0, * 1, 1, 1# */ #define _TO_BSIZE NPY_SIZEOF_@TO_BASENAME@ @@ -3499,11 +3520,13 @@ initialize_numeric_types(void) /**begin repeat * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, - * ulong, ulonglong, float, double, longdouble, cfloat, cdouble, - * clongdouble, string, unicode, void, object, datetime, timedelta# + * ulong, ulonglong, half, float, double, longdouble, cfloat, + * cdouble, clongdouble, string, unicode, void, object, datetime, + * timedelta# * #NAME = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, - * ULong, ULongLong, Float, Double, LongDouble, CFloat, CDouble, - * CLongDouble, String, Unicode, Void, Object, Datetime, Timedelta# + * ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, + * CDouble, CLongDouble, String, Unicode, Void, Object, Datetime, + * Timedelta# */ Py@NAME@ArrType_Type.tp_flags = BASEFLAGS; Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new; @@ -3512,11 +3535,11 @@ initialize_numeric_types(void) /**begin repeat * #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong, - * float, longdouble, cfloat, clongdouble, void, object, datetime, - * timedelta# + * half, float, longdouble, cfloat, clongdouble, void, object, + * datetime, timedelta# * #NAME = Bool, Byte, Short, UByte, UShort, UInt, ULong, ULongLong, - * Float, LongDouble, CFloat, CLongDouble, Void, Object, Datetime, - * Timedelta# + * Half, Float, LongDouble, CFloat, CLongDouble, Void, Object, + * Datetime, Timedelta# */ Py@NAME@ArrType_Type.tp_hash = @name@_arrtype_hash; /**end repeat**/ @@ -3546,6 +3569,8 @@ initialize_numeric_types(void) /**begin repeat * #name = repr, str# */ + PyHalfArrType_Type.tp_@name@ = halftype_@name@; + PyFloatArrType_Type.tp_@name@ = floattype_@name@; PyCFloatArrType_Type.tp_@name@ = cfloattype_@name@; @@ -3553,6 +3578,7 @@ initialize_numeric_types(void) PyCDoubleArrType_Type.tp_@name@ = cdoubletype_@name@; /**end repeat**/ + PyHalfArrType_Type.tp_print = halftype_print; PyFloatArrType_Type.tp_print = floattype_print; PyDoubleArrType_Type.tp_print = doubletype_print; PyLongDoubleArrType_Type.tp_print = longdoubletype_print; @@ -3608,6 +3634,7 @@ static PyTypeObject *typeobjects[] = { &PyULongArrType_Type, &PyLongLongArrType_Type, &PyULongLongArrType_Type, + &PyHalfArrType_Type, &PyFloatArrType_Type, &PyDoubleArrType_Type, &PyLongDoubleArrType_Type, diff --git a/numpy/core/src/npymath/halffloat.c b/numpy/core/src/npymath/halffloat.c new file mode 100644 index 000000000..da92d3e12 --- /dev/null +++ b/numpy/core/src/npymath/halffloat.c @@ -0,0 +1,525 @@ +#include "numpy/halffloat.h" +#include "numpy/ufuncobject.h" + +/* + * This chooses between 'ties to even' and 'ties away from zero'. + */ +#define NPY_HALF_ROUND_TIES_TO_EVEN 1 +/* + * If these are 1, the conversions try to trigger underflow, + * overflow, and invalid exceptions in the FP system when needed. + */ +#define NPY_HALF_GENERATE_OVERFLOW 1 +#define NPY_HALF_GENERATE_UNDERFLOW 1 +#define NPY_HALF_GENERATE_INVALID 1 + +/* + ******************************************************************** + * HALF-PRECISION ROUTINES * + ******************************************************************** + */ + +float npy_half_to_float(npy_half h) +{ + union { float ret; npy_uint32 retbits; } conv; + conv.retbits = npy_halfbits_to_floatbits(h); + return conv.ret; +} + +double npy_half_to_double(npy_half h) +{ + union { double ret; npy_uint64 retbits; } conv; + conv.retbits = npy_halfbits_to_doublebits(h); + return conv.ret; +} + +npy_half npy_float_to_half(float f) +{ + union { float f; npy_uint32 fbits; } conv; + conv.f = f; + return npy_floatbits_to_halfbits(conv.fbits); +} + +npy_half npy_double_to_half(double d) +{ + union { double d; npy_uint64 dbits; } conv; + conv.d = d; + return npy_doublebits_to_halfbits(conv.dbits); +} + +int npy_half_iszero(npy_half h) +{ + return (h&0x7fff) == 0; +} + +int npy_half_isnan(npy_half h) +{ + return ((h&0x7c00u) == 0x7c00u) && ((h&0x03ffu) != 0x0000u); +} + +int npy_half_isinf(npy_half h) +{ + return ((h&0x7fffu) == 0x7c00u); +} + +int npy_half_isfinite(npy_half h) +{ + return ((h&0x7c00u) != 0x7c00u); +} + +int npy_half_signbit(npy_half h) +{ + return (h&0x8000u) != 0; +} + +npy_half npy_half_spacing(npy_half h) +{ + npy_half ret; + npy_uint16 h_exp = h&0x7c00u; + npy_uint16 h_sig = h&0x03ffu; + if (h_exp == 0x7c00u || h == 0x7bffu) { +#if NPY_HALF_GENERATE_INVALID + generate_invalid_error(); +#endif + ret = NPY_HALF_NAN; + } else if ((h&0x8000u) && h_sig == 0) { /* Negative boundary case */ + if (h_exp > 0x2c00u) { /* If result is normalized */ + ret = h_exp - 0x2c00u; + } else if(h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */ + ret = 1 << ((h_exp >> 10) - 2); + } else { + ret = 0x0001u; /* Smallest subnormal half */ + } + } else if (h_exp > 0x2800u) { /* If result is still normalized */ + ret = h_exp - 0x2800u; + } else if (h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */ + ret = 1 << ((h_exp >> 10) - 1); + } else { + ret = 0x0001u; + } + + return ret; +} + +npy_half npy_half_copysign(npy_half x, npy_half y) +{ + return (x&0x7fffu) | (y&0x8000u); +} + +npy_half npy_half_nextafter(npy_half x, npy_half y) +{ + npy_half ret; + + if (!npy_half_isfinite(x) || npy_half_isnan(y)) { +#if NPY_HALF_GENERATE_INVALID + generate_invalid_error(); +#endif + ret = NPY_HALF_NAN; + } else if (npy_half_eq_nonan(x, y)) { + ret = x; + } else if (npy_half_iszero(x)) { + ret = (y&0x8000u) + 1; /* Smallest subnormal half */ + } else if (!(x&0x8000u)) { /* x > 0 */ + if ((npy_int16)x > (npy_int16)y) { /* x > y */ + ret = x-1; + } else { + ret = x+1; + } + } else { + if (!(y&0x8000u) || (x&0x7fffu) > (y&0x7fffu)) { /* x < y */ + ret = x-1; + } else { + ret = x+1; + } + } +#ifdef NPY_HALF_GENERATE_OVERFLOW + if (npy_half_isinf(ret)) { + generate_overflow_error(); + } +#endif + + return ret; +} + +int npy_half_eq_nonan(npy_half h1, npy_half h2) +{ + return (h1 == h2 || ((h1 | h2) & 0x7fff) == 0); +} + +int npy_half_eq(npy_half h1, npy_half h2) +{ + /* + * The equality cases are as follows: + * - If either value is NaN, never equal. + * - If the values are equal, equal. + * - If the values are both signed zeros, equal. + */ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && + (h1 == h2 || ((h1 | h2) & 0x7fff) == 0); +} + +int npy_half_ne(npy_half h1, npy_half h2) +{ + return !npy_half_eq(h1, h2); +} + +int npy_half_lt_nonan(npy_half h1, npy_half h2) +{ + if (h1&0x8000u) { + if (h2&0x8000u) { + return (h1&0x7fffu) > (h2&0x7fffu); + } else { + /* Signed zeros are equal, have to check for it */ + return (h1 != 0x8000u) || (h2 != 0x0000u); + } + } else { + if (h2&0x8000u) { + return 0; + } else { + return (h1&0x7fffu) < (h2&0x7fffu); + } + } +} + +int npy_half_lt(npy_half h1, npy_half h2) +{ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_lt_nonan(h1, h2); +} + +int npy_half_gt(npy_half h1, npy_half h2) +{ + return npy_half_lt(h2, h1); +} + +int npy_half_le_nonan(npy_half h1, npy_half h2) +{ + if (h1&0x8000u) { + if (h2&0x8000u) { + return (h1&0x7fffu) >= (h2&0x7fffu); + } else { + return 1; + } + } else { + if (h2&0x8000u) { + /* Signed zeros are equal, have to check for it */ + return (h1 == 0x0000u) && (h2 == 0x8000u); + } else { + return (h1&0x7fffu) <= (h2&0x7fffu); + } + } +} + +int npy_half_le(npy_half h1, npy_half h2) +{ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_le_nonan(h1, h2); +} + +int npy_half_ge(npy_half h1, npy_half h2) +{ + return npy_half_le(h2, h1); +} + + + +/* + ******************************************************************** + * BIT-LEVEL CONVERSIONS * + ******************************************************************** + */ + +npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f) +{ + npy_uint32 f_exp, f_sig; + npy_uint16 h_sgn, h_exp, h_sig; + + h_sgn = (npy_uint16) ((f&0x80000000u) >> 16); + f_exp = (f&0x7f800000u); + + /* Exponent overflow/NaN converts to signed inf/NaN */ + if (f_exp >= 0x47800000u) { + if (f_exp == 0x7f800000u) { + /* Inf or NaN */ + f_sig = (f&0x007fffffu); + if (f_sig != 0) { + /* NaN - propagate the flag in the significand... */ + npy_uint16 ret = (npy_uint16) (0x7c00u + (f_sig >> 13)); + /* ...but make sure it stays a NaN */ + if (ret == 0x7c00u) { + ret++; + } + return h_sgn + ret; + } else { + /* signed inf */ + return (npy_uint16) (h_sgn + 0x7c00u); + } + } else { + /* overflow to signed inf */ +#if NPY_HALF_GENERATE_OVERFLOW + generate_overflow_error(); +#endif + return (npy_uint16) (h_sgn + 0x7c00u); + } + } + + /* Exponent underflow converts to a subnormal half or signed zero */ + if (f_exp <= 0x38000000u) { + /* + * Signed zeros, subnormal floats, and floats with small + * exponents all convert to signed zero halfs. + */ + if (f_exp < 0x33000000u) { +#if NPY_HALF_GENERATE_UNDERFLOW + /* If f != 0, it underflowed to 0 */ + if ((f&0x7fffffff) != 0) { + generate_underflow_error(); + } +#endif + return h_sgn; + } + /* Make the subnormal significand */ + f_exp >>= 23; + f_sig = (0x00800000u + (f&0x007fffffu)); +#if NPY_HALF_GENERATE_UNDERFLOW + /* If it's not exactly represented, it underflowed */ + if ((f_sig&(((npy_uint32)1 << (126 - f_exp)) - 1)) != 0) { + generate_underflow_error(); + } +#endif + f_sig >>= (113 - f_exp); + /* Handle rounding by adding 1 to the bit beyond half precision */ +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((f_sig&0x00003fffu) != 0x00001000u) { + f_sig += 0x00001000u; + } +#else + f_sig += 0x00001000u; +#endif + h_sig = (npy_uint16) (f_sig >> 13); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp from zero to one and h_sig will be zero. + * This is the correct result. + */ + return (npy_uint16) (h_sgn + h_sig); + } + + /* Regular case with no overflow or underflow */ + h_exp = (npy_uint16) ((f_exp - 0x38000000u) >> 13); + /* Handle rounding by adding 1 to the bit beyond half precision */ + f_sig = (f&0x007fffffu); +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((f_sig&0x00003fffu) != 0x00001000u) { + f_sig += 0x00001000u; + } +#else + f_sig += 0x00001000u; +#endif + h_sig = (npy_uint16) (f_sig >> 13); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp by one and h_sig will be zero. This is the + * correct result. h_exp may increment to 15, at greatest, in + * which case the result overflows to a signed inf. + */ +#if NPY_HALF_GENERATE_OVERFLOW + h_sig += h_exp; + if (h_sig == 0x7c00u) { + generate_overflow_error(); + } + return h_sgn + h_sig; +#else + return h_sgn + h_exp + h_sig; +#endif +} + +npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d) +{ + npy_uint64 d_exp, d_sig; + npy_uint16 h_sgn, h_exp, h_sig; + + h_sgn = (d&0x8000000000000000u) >> 48; + d_exp = (d&0x7ff0000000000000u); + + /* Exponent overflow/NaN converts to signed inf/NaN */ + if (d_exp >= 0x40f0000000000000u) { + if (d_exp == 0x7ff0000000000000u) { + /* Inf or NaN */ + d_sig = (d&0x000fffffffffffffu); + if (d_sig != 0) { + /* NaN - propagate the flag in the significand... */ + npy_uint16 ret = (npy_uint16) (0x7c00u + (d_sig >> 42)); + /* ...but make sure it stays a NaN */ + if (ret == 0x7c00u) { + ret++; + } + return h_sgn + ret; + } else { + /* signed inf */ + return h_sgn + 0x7c00u; + } + } else { + /* overflow to signed inf */ +#if NPY_HALF_GENERATE_OVERFLOW + generate_overflow_error(); +#endif + return h_sgn + 0x7c00u; + } + } + + /* Exponent underflow converts to subnormal half or signed zero */ + if (d_exp <= 0x3f00000000000000u) { + /* + * Signed zeros, subnormal floats, and floats with small + * exponents all convert to signed zero halfs. + */ + if (d_exp < 0x3e60000000000000u) { +#if NPY_HALF_GENERATE_UNDERFLOW + /* If d != 0, it underflowed to 0 */ + if ((d&0x7fffffffffffffff) != 0) { + generate_underflow_error(); + } +#endif + return h_sgn; + } + /* Make the subnormal significand */ + d_exp >>= 52; + d_sig = (0x0010000000000000u + (d&0x000fffffffffffffu)); +#if NPY_HALF_GENERATE_UNDERFLOW + /* If it's not exactly represented, it underflowed */ + if ((d_sig&(((npy_uint64)1 << (1051 - d_exp)) - 1)) != 0) { + generate_underflow_error(); + } +#endif + d_sig >>= (1009 - d_exp); + /* Handle rounding by adding 1 to the bit beyond half precision */ +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((d_sig&0x000007ffffffffffu) != 0x0000020000000000u) { + d_sig += 0x0000020000000000u; + } +#else + d_sig += 0x0000020000000000u; +#endif + h_sig = (npy_uint16) (d_sig >> 42); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp from zero to one and h_sig will be zero. + * This is the correct result. + */ + return h_sgn + h_sig; + } + + /* Regular case with no overflow or underflow */ + h_exp = (npy_uint16) ((d_exp - 0x3f00000000000000u) >> 42); + /* Handle rounding by adding 1 to the bit beyond half precision */ + d_sig = (d&0x000fffffffffffffu); +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((d_sig&0x000007ffffffffffu) != 0x0000020000000000u) { + d_sig += 0x0000020000000000u; + } +#else + d_sig += 0x0000020000000000u; +#endif + h_sig = (npy_uint16) (d_sig >> 42); + + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp by one and h_sig will be zero. This is the + * correct result. h_exp may increment to 15, at greatest, in + * which case the result overflows to a signed inf. + */ +#if NPY_HALF_GENERATE_OVERFLOW + h_sig += h_exp; + if (h_sig == 0x7c00u) { + generate_overflow_error(); + } + return h_sgn + h_sig; +#else + return h_sgn + h_exp + h_sig; +#endif +} + +npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h) +{ + npy_uint16 h_exp, h_sig; + npy_uint32 f_sgn, f_exp, f_sig; + + h_exp = (h&0x7c00u); + f_sgn = ((npy_uint32)h&0x8000u) << 16; + switch (h_exp) { + case 0x0000u: /* 0 or subnormal */ + h_sig = (h&0x03ffu); + /* Signed zero */ + if (h_sig == 0) { + return f_sgn; + } + /* Subnormal */ + h_sig <<= 1; + while ((h_sig&0x0400u) == 0) { + h_sig <<= 1; + h_exp++; + } + f_exp = ((npy_uint32)(127 - 15 - h_exp)) << 23; + f_sig = ((npy_uint32)(h_sig&0x03ffu)) << 13; + return f_sgn + f_exp + f_sig; + case 0x7c00u: /* inf or NaN */ + /* All-ones exponent and a copy of the significand */ + return f_sgn + 0x7f800000u + (((npy_uint32)(h&0x03ffu)) << 13); + default: /* normalized */ + /* Just need to adjust the exponent and shift */ + return f_sgn + (((npy_uint32)(h&0x7fffu) + 0x1c000u) << 13); + } +} + +npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h) +{ + npy_uint16 h_exp, h_sig; + npy_uint64 d_sgn, d_exp, d_sig; + + h_exp = (h&0x7c00u); + d_sgn = ((npy_uint64)h&0x8000u) << 48; + switch (h_exp) { + case 0x0000u: /* 0 or subnormal */ + h_sig = (h&0x03ffu); + /* Signed zero */ + if (h_sig == 0) { + return d_sgn; + } + /* Subnormal */ + h_sig <<= 1; + while ((h_sig&0x0400u) == 0) { + h_sig <<= 1; + h_exp++; + } + d_exp = ((npy_uint64)(1023 - 15 - h_exp)) << 52; + d_sig = ((npy_uint64)(h_sig&0x03ffu)) << 42; + return d_sgn + d_exp + d_sig; + case 0x7c00u: /* inf or NaN */ + /* All-ones exponent and a copy of the significand */ + return d_sgn + 0x7ff0000000000000u + + (((npy_uint64)(h&0x03ffu)) << 42); + default: /* normalized */ + /* Just need to adjust the exponent and shift */ + return d_sgn + (((npy_uint64)(h&0x7fffu) + 0xfc000u) << 42); + } +} + diff --git a/numpy/core/src/scalarmathmodule.c.src b/numpy/core/src/scalarmathmodule.c.src index c4e6263ba..712932958 100644 --- a/numpy/core/src/scalarmathmodule.c.src +++ b/numpy/core/src/scalarmathmodule.c.src @@ -13,6 +13,8 @@ #include "numpy/npy_3kcompat.h" +#include "numpy/halffloat.h" + /** numarray adapted routines.... **/ #if SIZEOF_LONGLONG == 64 || SIZEOF_LONGLONG == 128 @@ -352,6 +354,17 @@ static @name@ (*_basic_@name@_fmod)(@name@, @name@); *(outp) = _basic_@name@_floor((a) / (b)) /**end repeat**/ +static npy_half (*_basic_half_floor)(npy_half); +static npy_half (*_basic_half_sqrt)(npy_half); +static npy_half (*_basic_half_fmod)(npy_half, npy_half); +#define half_ctype_add(a, b, outp) *(outp) = npy_float_to_half(npy_half_to_float(a) + npy_half_to_float(b)) +#define half_ctype_subtract(a, b, outp) *(outp) = npy_float_to_half(npy_half_to_float(a) - npy_half_to_float(b)) +#define half_ctype_multiply(a, b, outp) *(outp) = npy_float_to_half(npy_half_to_float(a) * npy_half_to_float(b)) +#define half_ctype_divide(a, b, outp) *(outp) = npy_float_to_half(npy_half_to_float(a) / npy_half_to_float(b)) +#define half_ctype_true_divide half_ctype_divide +#define half_ctype_floor_divide(a, b, outp) \ + *(outp) = npy_float_to_half(_basic_float_floor(npy_half_to_float(a) / npy_half_to_float(b))) + /**begin repeat * #name = cfloat, cdouble, clongdouble# * #rtype = float, double, longdouble# @@ -397,11 +410,20 @@ static void } /**end repeat**/ +static void +half_ctype_remainder(npy_half a, npy_half b, npy_half *out) { + float mod, fa = npy_half_to_float(a), fb = npy_half_to_float(b); + mod = _basic_float_fmod(fa, fb); + if (mod && (((fb < 0) != (mod < 0)))) { + mod += fb; + } + *out = npy_float_to_half(mod); +} /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, long, ulong, longlong, - * ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble# + * ulonglong, half, float, double, longdouble, cfloat, cdouble, clongdouble# */ #define @name@_ctype_divmod(a, b, out, out2) { \ @name@_ctype_floor_divide(a, b, out); \ @@ -410,11 +432,11 @@ static void /**end repeat**/ /**begin repeat - * #name = float, double, longdouble# + * #name = half, float, double, longdouble# */ -static @name@ (*_basic_@name@_pow)(@name@ a, @name@ b); +static npy_@name@ (*_basic_@name@_pow)(npy_@name@ a, npy_@name@ b); static void -@name@_ctype_power(@name@ a, @name@ b, @name@ *out) { +@name@_ctype_power(npy_@name@ a, npy_@name@ b, npy_@name@ *out) { *out = _basic_@name@_pow(a, b); } /**end repeat**/ @@ -425,7 +447,7 @@ static void * #uns = (0,1)*5,0*3# */ static void -@name@_ctype_negative(@name@ a, @name@ *out) +@name@_ctype_negative(npy_@name@ a, npy_@name@ *out) { #if @uns@ generate_overflow_error(); @@ -434,6 +456,12 @@ static void } /**end repeat**/ +static void +half_ctype_negative(npy_half a, npy_half *out) +{ + *out = a^0x8000u; +} + /**begin repeat * #name = cfloat, cdouble, clongdouble# @@ -448,10 +476,10 @@ static void /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, long, ulong, longlong, - * ulonglong, float, double, longdouble# + * ulonglong, half, float, double, longdouble# */ static void -@name@_ctype_positive(@name@ a, @name@ *out) +@name@_ctype_positive(npy_@name@ a, npy_@name@ *out) { *out = a; } @@ -497,6 +525,12 @@ static void } /**end repeat**/ +static void +half_ctype_absolute(npy_half a, npy_half *out) +{ + *out = a&0x7fffu; +} + /**begin repeat * #name = cfloat, cdouble, clongdouble# * #rname = float, double, longdouble# @@ -534,15 +568,15 @@ static void /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, long, ulong, longlong, - * ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble# + * ulonglong, half, float, double, longdouble, cfloat, cdouble, clongdouble# * #Name = Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, - * ULongLong, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# + * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# * #NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, - * ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE# + * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE# */ static int -_@name@_convert_to_ctype(PyObject *a, @name@ *arg1) +_@name@_convert_to_ctype(PyObject *a, npy_@name@ *arg1) { PyObject *temp; @@ -585,11 +619,11 @@ _@name@_convert_to_ctype(PyObject *a, @name@ *arg1) /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong, float, double, cfloat, cdouble# + * longlong, ulonglong, half, float, double, cfloat, cdouble# */ static int -_@name@_convert2_to_ctypes(PyObject *a, @name@ *arg1, - PyObject *b, @name@ *arg2) +_@name@_convert2_to_ctypes(PyObject *a, npy_@name@ *arg1, + PyObject *b, npy_@name@ *arg2) { int ret; ret = _@name@_convert_to_ctype(a, arg1); @@ -635,14 +669,32 @@ _@name@_convert2_to_ctypes(PyObject *a, @name@ *arg1, #endif /**begin repeat - #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong)*13, (float, double, longdouble, cfloat, cdouble, clongdouble)*6, (float, double, longdouble)*2# - #Name=(Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong)*13, (Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*6, (Float, Double, LongDouble)*2# - #oper=add*10, subtract*10, multiply*10, divide*10, remainder*10, divmod*10, floor_divide*10, lshift*10, rshift*10, and*10, or*10, xor*10, true_divide*10, add*6, subtract*6, multiply*6, divide*6, floor_divide*6, true_divide*6, divmod*3, remainder*3# - #fperr=1*70,0*50,1*52# - #twoout=0*50,1*10,0*106,1*3,0*3# - #otyp=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong)*12, float*4, double*6, (float, double, longdouble, cfloat, cdouble, clongdouble)*6, (float, double, longdouble)*2# - #OName=(Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong)*12, Float*4, Double*6, (Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*6, (Float, Double, LongDouble)*2# -**/ + * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong)*13, + * (half, float, double, longdouble, cfloat, cdouble, clongdouble)*6, + * (half, float, double, longdouble)*2# + * #Name=(Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong)*13, + * (Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*6, + * (Half, Float, Double, LongDouble)*2# + * #oper=add*10, subtract*10, multiply*10, divide*10, remainder*10, + * divmod*10, floor_divide*10, lshift*10, rshift*10, and*10, + * or*10, xor*10, true_divide*10, + * add*7, subtract*7, multiply*7, divide*7, floor_divide*7, true_divide*7, + * divmod*4, remainder*4# + * #fperr=1*70,0*50,1*10, + * 1*42, + * 1*8# + * #twoout=0*50,1*10,0*70, + * 0*42, + * 1*4,0*4# + * #otyp=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong)*12, + * float*4, double*6, + * (half, float, double, longdouble, cfloat, cdouble, clongdouble)*6, + * (half, float, double, longdouble)*2# + * #OName=(Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong)*12, + * Float*4, Double*6, + * (Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*6, + * (Half, Float, Double, LongDouble)*2# + */ #if !defined(CODEGEN_SKIP_@oper@_FLAG) @@ -650,16 +702,16 @@ static PyObject * @name@_@oper@(PyObject *a, PyObject *b) { PyObject *ret; - @name@ arg1, arg2; + npy_@name@ arg1, arg2; /* * NOTE: In gcc >= 4.1, the compiler will reorder floating point operations and * floating point error state checks. In particular, the arithmetic operations * were being reordered so that the errors weren't caught. Declaring this output * variable volatile was the minimal fix for the issue. (Ticket #1671) */ - volatile @otyp@ out; + volatile npy_@otyp@ out; #if @twoout@ - @otyp@ out2; + npy_@otyp@ out2; PyObject *obj; #endif @@ -698,9 +750,9 @@ static PyObject * * as a function call. */ #if @twoout@ - @name@_ctype_@oper@(arg1, arg2, (@otyp@ *)&out, &out2); + @name@_ctype_@oper@(arg1, arg2, (npy_@otyp@ *)&out, &out2); #else - @name@_ctype_@oper@(arg1, arg2, (@otyp@ *)&out); + @name@_ctype_@oper@(arg1, arg2, (npy_@otyp@ *)&out); #endif #if @fperr@ @@ -758,30 +810,36 @@ static PyObject * #undef CODEGEN_SKIP_divide_FLAG +#define _IS_ZERO(x) (x ==0) /**begin repeat - #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float, double, longdouble, cfloat, cdouble, clongdouble# - #Name=Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# - #otyp=float*4, double*6, float, double, longdouble, cfloat, cdouble, clongdouble# - #OName=Float*4, Double*6, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# - #isint=(1,0)*5,0*6# - #cmplx=0*13,1*3# -**/ + * #name=byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, + * half, float, double, longdouble, cfloat, cdouble, clongdouble# + * #Name=Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# + * #otyp=float*4, double*6, half, float, double, longdouble, cfloat, cdouble, clongdouble# + * #OName=Float*4, Double*6, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# + * #isint=(1,0)*5,0*7# + * #cmplx=0*14,1*3# + * #iszero=_IS_ZERO*10, npy_half_iszero, _IS_ZERO*6# + * #zero=0*10, NPY_HALF_ZERO, 0*6# + * #one=1*10, NPY_HALF_ONE, 1*6# + */ static PyObject * @name@_power(PyObject *a, PyObject *b, PyObject *NPY_UNUSED(c)) { PyObject *ret; - @name@ arg1, arg2; + npy_@name@ arg1, arg2; int retstatus; int first; #if @cmplx@ - @name@ out = {0,0}; - @otyp@ out1; - out1.real = out.imag = 0; + npy_@name@ out = {@zero@,@zero@}; + npy_@otyp@ out1; + out1.real = out.imag = @zero@; #else - @name@ out = 0; - @otyp@ out1=0; + npy_@name@ out = @zero@; + npy_@otyp@ out1 = @zero@; #endif switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { @@ -812,13 +870,13 @@ static PyObject * * as a function call. */ #if @cmplx@ - if (arg2.real == 0 && arg2.imag == 0) { - out1.real = out.real = 1; - out1.imag = out.imag = 0; + if (@iszero@(arg2.real) && @iszero@(arg2.imag)) { + out1.real = out.real = @one@; + out1.imag = out.imag = @zero@; } #else - if (arg2 == 0) { - out1 = out = 1; + if (@iszero@(arg2)) { + out1 = out = @one@; } #endif #if @isint@ @@ -875,6 +933,7 @@ static PyObject * return ret; } /**end repeat**/ +#undef _IS_ZERO /**begin repeat @@ -885,24 +944,29 @@ static PyObject * /**end repeat**/ /**begin repeat - * #name = (float,double,longdouble,cfloat,cdouble,clongdouble)*5# - * #oper = lshift*6, rshift*6, and*6, or*6, xor*6# + * #name = (half,float,double,longdouble,cfloat,cdouble,clongdouble)*5# + * #oper = lshift*7, rshift*7, and*7, or*7, xor*7# */ #define @name@_@oper@ NULL /**end repeat**/ /**begin repeat - * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble)*3, byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong# - * #otyp=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble)*2,byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,float,double,longdouble,byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong# - * #OName=(Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*2, Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Float, Double, LongDouble, Float, Double, LongDouble, Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong# - * #oper=negative*16, positive*16, absolute*16, invert*10# + * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble)*3, + * byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong# + * #otyp=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble)*2, + * byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,float,double,longdouble, + * byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong# + * #OName=(Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble)*2, + Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Half, Float, Double, LongDouble, Float, Double, LongDouble, + Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong# + * #oper=negative*17, positive*17, absolute*17, invert*10# */ static PyObject * @name@_@oper@(PyObject *a) { - @name@ arg1; - @otyp@ out; + npy_@name@ arg1; + npy_@otyp@ out; PyObject *ret; switch(_@name@_convert_to_ctype(a, &arg1)) { @@ -935,7 +999,7 @@ static PyObject * /**end repeat**/ /**begin repeat - * #name = float, double, longdouble, cfloat, cdouble, clongdouble# + * #name = half, float, double, longdouble, cfloat, cdouble, clongdouble# */ #define @name@_invert NULL /**end repeat**/ @@ -946,16 +1010,18 @@ static PyObject * #define NONZERO_NAME(prefix, suffix) prefix##nonzero##suffix #endif +#define _IS_NONZERO(x) (x != 0) /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, long, ulong, longlong, - * ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble# - * #simp=1*13,0*3# + * ulonglong, half, float, double, longdouble, cfloat, cdouble, clongdouble# + * #simp=1*14,0*3# + * #nonzero=_IS_NONZERO*10, !npy_half_iszero, _IS_NONZERO*6# */ static int NONZERO_NAME(@name@_,)(PyObject *a) { int ret; - @name@ arg1; + npy_@name@ arg1; if (_@name@_convert_to_ctype(a, &arg1) < 0) { if (PyErr_Occurred()) { @@ -970,21 +1036,21 @@ NONZERO_NAME(@name@_,)(PyObject *a) */ #if @simp@ - ret = (arg1 != 0); + ret = @nonzero@(arg1); #else - ret = ((arg1.real != 0) || (arg1.imag != 0)); + ret = (@nonzero@(arg1.real) || @nonzero@(arg1.imag)); #endif return ret; } /**end repeat**/ +#undef _IS_NONZERO static int emit_complexwarning() { static PyObject *cls = NULL; - int ret; if (cls == NULL) { PyObject *mod; mod = PyImport_ImportModule("numpy.core"); @@ -1006,23 +1072,24 @@ emit_complexwarning() /**begin repeat * - * #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble# - * #Name=Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong,Float,Double,LongDouble,CFloat,CDouble,CLongDouble# - * #cmplx=0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1# - * #sign=(signed,unsigned)*5,,,,,,# - * #unsigntyp=0,1,0,1,0,1,0,1,0,1,0*6# - * #ctype=long*8,PY_LONG_LONG*2,double*6# - * #realtyp=0*10,1*6# - * #func=(PyLong_FromLong,PyLong_FromUnsignedLong)*4,PyLong_FromLongLong,PyLong_FromUnsignedLongLong,PyLong_FromDouble*6# + * #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble# + * #Name=Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong,Half,Float,Double,LongDouble,CFloat,CDouble,CLongDouble# + * #cmplx=0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1# + * #sign=(signed,unsigned)*5,,,,,,,# + * #unsigntyp=0,1,0,1,0,1,0,1,0,1,0*7# + * #ctype=long*8,PY_LONG_LONG*2,double*7# + * #to_ctype=,,,,,,,,,,npy_half_to_double,,,,,,# + * #realtyp=0*10,1*7# + * #func=(PyLong_FromLong,PyLong_FromUnsignedLong)*4,PyLong_FromLongLong,PyLong_FromUnsignedLongLong,PyLong_FromDouble*7# */ static PyObject * @name@_int(PyObject *obj) { #if @cmplx@ - @sign@ @ctype@ x= PyArrayScalar_VAL(obj, @Name@).real; + @sign@ @ctype@ x= @to_ctype@(PyArrayScalar_VAL(obj, @Name@).real); int ret; #else - @sign@ @ctype@ x= PyArrayScalar_VAL(obj, @Name@); + @sign@ @ctype@ x= @to_ctype@(PyArrayScalar_VAL(obj, @Name@)); #endif #if @realtyp@ double ix; @@ -1049,11 +1116,12 @@ static PyObject * /**begin repeat * - * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble)*2# - * #Name=(Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong,Float,Double,LongDouble,CFloat,CDouble,CLongDouble)*2# - * #cmplx=(0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1)*2# - * #which=long*16,float*16# - * #func=(PyLong_FromLongLong, PyLong_FromUnsignedLongLong)*5,PyLong_FromDouble*6,PyFloat_FromDouble*16# + * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble)*2# + * #Name=(Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong,Half,Float,Double,LongDouble,CFloat,CDouble,CLongDouble)*2# + * #cmplx=(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1)*2# + * #to_ctype=(,,,,,,,,,,npy_half_to_double,,,,,,)*2# + * #which=long*17,float*17# + * #func=(PyLong_FromLongLong, PyLong_FromUnsignedLongLong)*5,PyLong_FromDouble*7,PyFloat_FromDouble*17# */ static PyObject * @name@_@which@(PyObject *obj) @@ -1064,9 +1132,9 @@ static PyObject * if (ret < 0) { return NULL; } - return @func@((PyArrayScalar_VAL(obj, @Name@)).real); + return @func@(@to_ctype@((PyArrayScalar_VAL(obj, @Name@)).real)); #else - return @func@((PyArrayScalar_VAL(obj, @Name@))); + return @func@(@to_ctype@(PyArrayScalar_VAL(obj, @Name@))); #endif } /**end repeat**/ @@ -1075,10 +1143,10 @@ static PyObject * /**begin repeat * - * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble)*2# - * #oper=oct*16, hex*16# - * #kind=(int*5, long*5, int, long*2, int, long*2)*2# - * #cap=(Int*5, Long*5, Int, Long*2, Int, Long*2)*2# + * #name=(byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble)*2# + * #oper=oct*17, hex*17# + * #kind=(int*5, long*5, int*2, long*2, int, long*2)*2# + * #cap=(Int*5, Long*5, Int*2, Long*2, Int, Long*2)*2# */ static PyObject * @name@_@oper@(PyObject *obj) @@ -1095,21 +1163,23 @@ static PyObject * /**begin repeat * #oper=le,ge,lt,gt,eq,ne# * #op=<=,>=,<,>,==,!=# + * #halfop=npy_half_le,npy_half_ge,npy_half_lt,npy_half_gt,npy_half_eq,npy_half_ne# */ #define def_cmp_@oper@(arg1, arg2) (arg1 @op@ arg2) #define cmplx_cmp_@oper@(arg1, arg2) ((arg1.real == arg2.real) ? \ arg1.imag @op@ arg2.imag : \ arg1.real @op@ arg2.real) +#define def_half_cmp_@oper@(arg1, arg2) @halfop@(arg1, arg2) /**end repeat**/ /**begin repeat - * #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble# - * #simp=def*13,cmplx*3# + * #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble# + * #simp=def*10,def_half,def*3,cmplx*3# */ static PyObject* @name@_richcompare(PyObject *self, PyObject *other, int cmp_op) { - @name@ arg1, arg2; + npy_@name@ arg1, arg2; int out=0; switch(_@name@_convert2_to_ctypes(self, &arg1, other, &arg2)) { @@ -1158,7 +1228,7 @@ static PyObject* /**begin repeat - #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble# + #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,half,float,double,longdouble,cfloat,cdouble,clongdouble# **/ static PyNumberMethods @name@_as_number = { (binaryfunc)@name@_add, /*nb_add*/ @@ -1231,8 +1301,8 @@ static void add_scalarmath(void) { /**begin repeat - #name=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble# - #NAME=Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# + #name=byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, half, float, double, longdouble, cfloat, cdouble, clongdouble# + #NAME=Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble# **/ #if PY_VERSION_HEX >= 0x02050000 @name@_as_number.nb_index = Py@NAME@ArrType_Type.tp_as_number->nb_index; @@ -1280,6 +1350,7 @@ get_functions(void) i = 0; j = 0; while(signatures[i] != PyArray_FLOAT) {i+=3; j++;} + _basic_half_pow = funcdata[j-1]; _basic_float_pow = funcdata[j]; _basic_double_pow = funcdata[j+1]; _basic_longdouble_pow = funcdata[j+2]; @@ -1296,6 +1367,7 @@ get_functions(void) i = 0; j = 0; while(signatures[i] != PyArray_FLOAT) {i+=2; j++;} + _basic_half_floor = funcdata[j-1]; _basic_float_floor = funcdata[j]; _basic_double_floor = funcdata[j+1]; _basic_longdouble_floor = funcdata[j+2]; @@ -1309,6 +1381,7 @@ get_functions(void) i = 0; j = 0; while(signatures[i] != PyArray_FLOAT) {i+=2; j++;} + _basic_half_sqrt = funcdata[j-1]; _basic_float_sqrt = funcdata[j]; _basic_double_sqrt = funcdata[j+1]; _basic_longdouble_sqrt = funcdata[j+2]; @@ -1322,6 +1395,7 @@ get_functions(void) i = 0; j = 0; while(signatures[i] != PyArray_FLOAT) {i+=3; j++;} + _basic_half_fmod = funcdata[j-1]; _basic_float_fmod = funcdata[j]; _basic_double_fmod = funcdata[j+1]; _basic_longdouble_fmod = funcdata[j+2]; diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index c61d16ae4..0c777e464 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -13,11 +13,13 @@ #include "numpy/noprefix.h" #include "numpy/ufuncobject.h" #include "numpy/npy_math.h" +#include "numpy/halffloat.h" #include "numpy/npy_3kcompat.h" #include "ufunc_object.h" + /* ***************************************************************************** ** UFUNC LOOPS ** @@ -56,13 +58,17 @@ intp i;\ for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1) -#define BINARY_REDUCE_LOOP(TYPE)\ - char *iop1 = args[0], *ip2 = args[1]; \ +#define BINARY_REDUCE_LOOP_INNER\ + char *ip2 = args[1]; \ intp is2 = steps[1]; \ intp n = dimensions[0]; \ intp i; \ - TYPE io1 = *(TYPE *)iop1; \ for(i = 0; i < n; i++, ip2 += is2) + +#define BINARY_REDUCE_LOOP(TYPE)\ + char *iop1 = args[0]; \ + TYPE io1 = *(TYPE *)iop1; \ + BINARY_REDUCE_LOOP_INNER #define BINARY_LOOP_TWO_OUT\ char *ip1 = args[0], *ip2 = args[1], *op1 = args[2], *op2 = args[3];\ @@ -76,9 +82,11 @@ *****************************************************************************/ +typedef float halfUnaryFunc(npy_half x); typedef float floatUnaryFunc(float x); typedef double doubleUnaryFunc(double x); typedef longdouble longdoubleUnaryFunc(longdouble x); +typedef npy_half halfBinaryFunc(npy_half x, npy_half y); typedef float floatBinaryFunc(float x, float y); typedef double doubleBinaryFunc(double x, double y); typedef longdouble longdoubleBinaryFunc(longdouble x, longdouble y); @@ -86,6 +94,39 @@ typedef longdouble longdoubleBinaryFunc(longdouble x, longdouble y); /*UFUNC_API*/ NPY_NO_EXPORT void +PyUFunc_e_e(char **args, intp *dimensions, intp *steps, void *func) +{ + halfUnaryFunc *f = (halfUnaryFunc *)func; + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *(npy_half *)op1 = f(in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_e_e_As_f_f(char **args, intp *dimensions, intp *steps, void *func) +{ + floatUnaryFunc *f = (floatUnaryFunc *)func; + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *(npy_half *)op1 = npy_float_to_half(f(in1)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_e_e_As_d_d(char **args, intp *dimensions, intp *steps, void *func) +{ + doubleUnaryFunc *f = (doubleUnaryFunc *)func; + UNARY_LOOP { + const double in1 = npy_half_to_double(*(npy_half *)ip1); + *(npy_half *)op1 = npy_double_to_half(f(in1)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void PyUFunc_f_f(char **args, intp *dimensions, intp *steps, void *func) { floatUnaryFunc *f = (floatUnaryFunc *)func; @@ -108,6 +149,42 @@ PyUFunc_f_f_As_d_d(char **args, intp *dimensions, intp *steps, void *func) /*UFUNC_API*/ NPY_NO_EXPORT void +PyUFunc_ee_e(char **args, intp *dimensions, intp *steps, void *func) +{ + halfBinaryFunc *f = (halfBinaryFunc *)func; + BINARY_LOOP { + npy_half in1 = *(npy_half *)ip1; + npy_half in2 = *(npy_half *)ip2; + *(npy_half *)op1 = f(in1, in2); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ee_e_As_ff_f(char **args, intp *dimensions, intp *steps, void *func) +{ + floatBinaryFunc *f = (floatBinaryFunc *)func; + BINARY_LOOP { + float in1 = npy_half_to_float(*(npy_half *)ip1); + float in2 = npy_half_to_float(*(npy_half *)ip2); + *(npy_half *)op1 = npy_float_to_half(f(in1, in2)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ee_e_As_dd_d(char **args, intp *dimensions, intp *steps, void *func) +{ + doubleBinaryFunc *f = (doubleBinaryFunc *)func; + BINARY_LOOP { + double in1 = npy_half_to_double(*(npy_half *)ip1); + double in2 = npy_half_to_double(*(npy_half *)ip2); + *(npy_half *)op1 = npy_double_to_half(f(in1, in2)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void PyUFunc_ff_f(char **args, intp *dimensions, intp *steps, void *func) { floatBinaryFunc *f = (floatBinaryFunc *)func; @@ -1053,8 +1130,6 @@ NPY_NO_EXPORT void } /**end repeat1**/ -/**end repeat1**/ - /**begin repeat1 * #kind = equal, not_equal, less, less_equal, greater, greater_equal, * logical_and, logical_or# @@ -1322,6 +1397,311 @@ NPY_NO_EXPORT void /**end repeat**/ +/* + ***************************************************************************** + ** HALF-FLOAT LOOPS ** + ***************************************************************************** + */ + + +/**begin repeat + * Arithmetic + * # kind = add, subtract, multiply, divide# + * # OP = +, -, *, /# + */ +NPY_NO_EXPORT void +HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + if(IS_BINARY_REDUCE) { + char *iop1 = args[0]; + float io1 = npy_half_to_float(*(npy_half *)iop1); + BINARY_REDUCE_LOOP_INNER { + io1 @OP@= npy_half_to_float(*(npy_half *)ip2); + } + *((npy_half *)iop1) = npy_float_to_half(io1); + } + else { + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const float in2 = npy_half_to_float(*(npy_half *)ip2); + *((npy_half *)op1) = npy_float_to_half(in1 @OP@ in2); + } + } +} +/**end repeat**/ + +#define _HALF_LOGICAL_AND(a,b) (!npy_half_iszero(a) && !npy_half_iszero(b)) +#define _HALF_LOGICAL_OR(a,b) (!npy_half_iszero(a) || !npy_half_iszero(b)) +/**begin repeat + * #kind = equal, not_equal, less, less_equal, greater, greater_equal, + * logical_and, logical_or# + * #OP = npy_half_eq, npy_half_ne, npy_half_lt, npy_half_le, npy_half_gt, npy_half_ge, _HALF_LOGICAL_AND, _HALF_LOGICAL_OR# + */ +NPY_NO_EXPORT void +HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((Bool *)op1) = @OP@(in1, in2); + } +} +/**end repeat**/ +#undef _HALF_LOGICAL_AND +#undef _HALF_LOGICAL_OR + +NPY_NO_EXPORT void +HALF_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const int in1 = !npy_half_iszero(*(npy_half *)ip1); + const int in2 = !npy_half_iszero(*(npy_half *)ip2); + *((Bool *)op1)= (in1 && !in2) || (!in1 && in2); + } +} + +NPY_NO_EXPORT void +HALF_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((Bool *)op1) = npy_half_iszero(in1); + } +} + +/**begin repeat + * #kind = isnan, isinf, isfinite, signbit# + * #func = npy_half_isnan, npy_half_isinf, npy_half_isfinite, npy_half_signbit# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((Bool *)op1) = @func@(in1) != 0; + } +} +/**end repeat**/ + +NPY_NO_EXPORT void +HALF_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = npy_half_spacing(in1); + } +} + +NPY_NO_EXPORT void +HALF_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1)= npy_half_copysign(in1, in2); + } +} + +NPY_NO_EXPORT void +HALF_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1)= npy_half_nextafter(in1, in2); + } +} + +/**begin repeat + * #kind = maximum, minimum# + * #OP = npy_half_ge, npy_half_le# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2; + } +} +/**end repeat**/ + +/**begin repeat + * #kind = fmax, fmin# + * #OP = npy_half_ge, npy_half_le# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in2)) ? in1 : in2; + } +} +/**end repeat**/ + +NPY_NO_EXPORT void +HALF_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const float in2 = npy_half_to_float(*(npy_half *)ip2); + *((npy_half *)op1) = npy_float_to_half(npy_floorf(in1/in2)); + } +} + +NPY_NO_EXPORT void +HALF_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const float in2 = npy_half_to_float(*(npy_half *)ip2); + const float res = npy_fmodf(in1,in2); + if (res && ((in2 < 0) != (res < 0))) { + *((npy_half *)op1) = npy_float_to_half(res + in2); + } + else { + *((npy_half *)op1) = npy_float_to_half(res); + } + } +} + +NPY_NO_EXPORT void +HALF_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(in1*in1); + } +} + +NPY_NO_EXPORT void +HALF_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(1/in1); + } +} + +NPY_NO_EXPORT void +HALF_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((npy_half *)op1) = NPY_HALF_ONE; + } +} + +NPY_NO_EXPORT void +HALF_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1; + } +} + +NPY_NO_EXPORT void +HALF_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1&0x7fffu; + } +} + +NPY_NO_EXPORT void +HALF_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1^0x8000u; + } +} + +NPY_NO_EXPORT void +HALF_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + /* Sign of nan is nan */ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = npy_half_isnan(in1) ? in1 : + (((in1&0x7fffu) == 0) ? 0 : + (((in1&0x8000u) == 0) ? NPY_HALF_ONE : NPY_HALF_NEGONE)); + } +} + +NPY_NO_EXPORT void +HALF_modf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + float temp; + + UNARY_LOOP_TWO_OUT { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(npy_modff(in1, &temp)); + *((npy_half *)op2) = npy_float_to_half(temp); + } +} + +#ifdef HAVE_FREXPF +NPY_NO_EXPORT void +HALF_frexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_TWO_OUT { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(frexpf(in1, (int *)op2)); + } +} +#endif + +#ifdef HAVE_LDEXPF +NPY_NO_EXPORT void +HALF_ldexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const int in2 = *(int *)ip2; + *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, in2)); + } +} + +NPY_NO_EXPORT void +HALF_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) +{ + /* + * Additional loop to handle long integer inputs (cf. #866, #1633). + * long != int on many 64-bit platforms, so we need this second loop + * to handle the default integer type. + */ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const long in2 = *(long *)ip2; + if (((int)in2) == in2) { + /* Range OK */ + *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, ((int)in2))); + } + else { + /* + * Outside int range -- also ldexp will overflow in this case, + * given that exponent has less bits than int. + */ + if (in2 > 0) { + *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MAX_INT)); + } + else { + *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MIN_INT)); + } + } + } +} +#endif + +#define HALF_true_divide HALF_divide + /* ***************************************************************************** diff --git a/numpy/core/src/umath/loops.h b/numpy/core/src/umath/loops.h index 7cb4b22cc..2d8343b47 100644 --- a/numpy/core/src/umath/loops.h +++ b/numpy/core/src/umath/loops.h @@ -12,6 +12,20 @@ * vim:syntax=c */ +/* + ***************************************************************************** + ** IMPORTANT NOTE for loops.h.src -> loops.h ** + ***************************************************************************** + * The template file loops.h.src is not automatically converted into + * loops.h by the build system. If you edit this file, you must manually + * do the conversion using numpy/distutils/conv_template.py from the + * command line as follows: + * + * $ cd <NumPy source root directory> + * $ python numpy/distutils/conv_template.py numpy/core/src/umath/loops.h.src + * $ + */ + #ifndef _NPY_UMATH_LOOPS_H_ #define _NPY_UMATH_LOOPS_H_ @@ -32,116 +46,116 @@ ***************************************************************************** */ -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 32 +#line 46 NPY_NO_EXPORT void BOOL_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 41 +#line 55 NPY_NO_EXPORT void BOOL_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 41 +#line 55 NPY_NO_EXPORT void BOOL_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 49 +#line 63 NPY_NO_EXPORT void BOOL_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 49 +#line 63 NPY_NO_EXPORT void BOOL_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -155,9 +169,9 @@ BOOL_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data ***************************************************************************** */ -#line 67 +#line 81 -#line 73 +#line 87 #define BYTE_floor_divide BYTE_divide #define BYTE_fmax BYTE_maximum @@ -184,76 +198,76 @@ BYTE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void BYTE_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void BYTE_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void BYTE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -261,11 +275,11 @@ BYTE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun NPY_NO_EXPORT void BYTE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void BYTE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void BYTE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -280,7 +294,7 @@ NPY_NO_EXPORT void BYTE_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 73 +#line 87 #define UBYTE_floor_divide UBYTE_divide #define UBYTE_fmax UBYTE_maximum @@ -307,76 +321,76 @@ UBYTE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f NPY_NO_EXPORT void UBYTE_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UBYTE_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UBYTE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -384,11 +398,11 @@ UBYTE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void UBYTE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void UBYTE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void UBYTE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -428,9 +442,9 @@ BYTE_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func NPY_NO_EXPORT void UBYTE_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 67 +#line 81 -#line 73 +#line 87 #define SHORT_floor_divide SHORT_divide #define SHORT_fmax SHORT_maximum @@ -457,76 +471,76 @@ SHORT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f NPY_NO_EXPORT void SHORT_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void SHORT_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void SHORT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -534,11 +548,11 @@ SHORT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void SHORT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void SHORT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void SHORT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -553,7 +567,7 @@ NPY_NO_EXPORT void SHORT_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 73 +#line 87 #define USHORT_floor_divide USHORT_divide #define USHORT_fmax USHORT_maximum @@ -580,76 +594,76 @@ USHORT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED( NPY_NO_EXPORT void USHORT_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void USHORT_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void USHORT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -657,11 +671,11 @@ USHORT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f NPY_NO_EXPORT void USHORT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void USHORT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void USHORT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -701,9 +715,9 @@ SHORT_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun NPY_NO_EXPORT void USHORT_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 67 +#line 81 -#line 73 +#line 87 #define INT_floor_divide INT_divide #define INT_fmax INT_maximum @@ -730,76 +744,76 @@ INT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun NPY_NO_EXPORT void INT_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void INT_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void INT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -807,11 +821,11 @@ INT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func NPY_NO_EXPORT void INT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void INT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void INT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -826,7 +840,7 @@ NPY_NO_EXPORT void INT_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 73 +#line 87 #define UINT_floor_divide UINT_divide #define UINT_fmax UINT_maximum @@ -853,76 +867,76 @@ UINT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void UINT_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void UINT_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void UINT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -930,11 +944,11 @@ UINT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun NPY_NO_EXPORT void UINT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void UINT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void UINT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -974,9 +988,9 @@ INT_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func) NPY_NO_EXPORT void UINT_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 67 +#line 81 -#line 73 +#line 87 #define LONG_floor_divide LONG_divide #define LONG_fmax LONG_maximum @@ -1003,76 +1017,76 @@ LONG_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void LONG_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONG_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1080,11 +1094,11 @@ LONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun NPY_NO_EXPORT void LONG_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void LONG_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void LONG_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1099,7 +1113,7 @@ NPY_NO_EXPORT void LONG_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 73 +#line 87 #define ULONG_floor_divide ULONG_divide #define ULONG_fmax ULONG_maximum @@ -1126,76 +1140,76 @@ ULONG_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f NPY_NO_EXPORT void ULONG_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONG_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1203,11 +1217,11 @@ ULONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void ULONG_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void ULONG_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void ULONG_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1247,9 +1261,9 @@ LONG_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func NPY_NO_EXPORT void ULONG_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 67 +#line 81 -#line 73 +#line 87 #define LONGLONG_floor_divide LONGLONG_divide #define LONGLONG_fmax LONGLONG_maximum @@ -1276,76 +1290,76 @@ LONGLONG_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSE NPY_NO_EXPORT void LONGLONG_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void LONGLONG_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void LONGLONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1353,11 +1367,11 @@ LONGLONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED NPY_NO_EXPORT void LONGLONG_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void LONGLONG_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void LONGLONG_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1372,7 +1386,7 @@ NPY_NO_EXPORT void LONGLONG_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 73 +#line 87 #define ULONGLONG_floor_divide ULONGLONG_divide #define ULONGLONG_fmax ULONGLONG_maximum @@ -1399,76 +1413,76 @@ ULONGLONG_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUS NPY_NO_EXPORT void ULONGLONG_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_bitwise_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_bitwise_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_bitwise_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_left_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 105 +#line 119 NPY_NO_EXPORT void ULONGLONG_right_shift(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 115 +#line 129 NPY_NO_EXPORT void ULONGLONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1476,11 +1490,11 @@ ULONGLONG_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSE NPY_NO_EXPORT void ULONGLONG_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void ULONGLONG_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 126 +#line 140 NPY_NO_EXPORT void ULONGLONG_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1528,55 +1542,209 @@ ULONGLONG_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED */ -#line 180 +#line 194 + + +#line 201 +NPY_NO_EXPORT void +HALF_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 201 +NPY_NO_EXPORT void +HALF_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 201 +NPY_NO_EXPORT void +HALF_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 201 +NPY_NO_EXPORT void +HALF_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +#line 210 +NPY_NO_EXPORT void +HALF_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 210 +NPY_NO_EXPORT void +HALF_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 210 +NPY_NO_EXPORT void +HALF_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +#line 210 +NPY_NO_EXPORT void +HALF_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 210 +NPY_NO_EXPORT void +HALF_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 210 +NPY_NO_EXPORT void +HALF_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 210 +NPY_NO_EXPORT void +HALF_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 210 +NPY_NO_EXPORT void +HALF_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +NPY_NO_EXPORT void +HALF_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +HALF_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_signbit(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 224 +NPY_NO_EXPORT void +HALF_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +#line 232 +NPY_NO_EXPORT void +HALF_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 232 +NPY_NO_EXPORT void +HALF_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +#line 240 +NPY_NO_EXPORT void +HALF_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#line 240 +NPY_NO_EXPORT void +HALF_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +NPY_NO_EXPORT void +HALF_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +HALF_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +HALF_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +HALF_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)); + + +NPY_NO_EXPORT void +HALF_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +HALF_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +HALF_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +HALF_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +NPY_NO_EXPORT void +HALF_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + + +NPY_NO_EXPORT void +HALF_modf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + +#ifdef HAVE_FREXPF +NPY_NO_EXPORT void +HALF_frexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +#endif + +#ifdef HAVE_LDEXPF +NPY_NO_EXPORT void +HALF_ldexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void +HALF_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +#endif + +#define HALF_true_divide HALF_divide + + +#line 194 + + +#line 201 NPY_NO_EXPORT void FLOAT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void FLOAT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void FLOAT_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void FLOAT_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void FLOAT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1587,49 +1755,49 @@ FLOAT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f NPY_NO_EXPORT void FLOAT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_signbit(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void FLOAT_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void FLOAT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void FLOAT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void FLOAT_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void FLOAT_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1682,55 +1850,55 @@ FLOAT_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu #define FLOAT_true_divide FLOAT_divide -#line 180 +#line 194 -#line 187 +#line 201 NPY_NO_EXPORT void DOUBLE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void DOUBLE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void DOUBLE_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void DOUBLE_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void DOUBLE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1741,49 +1909,49 @@ DOUBLE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED( NPY_NO_EXPORT void DOUBLE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_signbit(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void DOUBLE_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void DOUBLE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void DOUBLE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void DOUBLE_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void DOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1836,55 +2004,55 @@ DOUBLE_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f #define DOUBLE_true_divide DOUBLE_divide -#line 180 +#line 194 -#line 187 +#line 201 NPY_NO_EXPORT void LONGDOUBLE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void LONGDOUBLE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void LONGDOUBLE_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 187 +#line 201 NPY_NO_EXPORT void LONGDOUBLE_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 196 +#line 210 NPY_NO_EXPORT void LONGDOUBLE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -1895,49 +2063,49 @@ LONGDOUBLE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNU NPY_NO_EXPORT void LONGDOUBLE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_signbit(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 210 +#line 224 NPY_NO_EXPORT void LONGDOUBLE_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void LONGDOUBLE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 218 +#line 232 NPY_NO_EXPORT void LONGDOUBLE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void LONGDOUBLE_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 226 +#line 240 NPY_NO_EXPORT void LONGDOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2005,14 +2173,14 @@ LONGDOUBLE_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUS #define CEQ(xr,xi,yr,yi) (xr == yr && xi == yi); #define CNE(xr,xi,yr,yi) (xr != yr || xi != yi); -#line 298 +#line 314 -#line 304 +#line 320 NPY_NO_EXPORT void CFLOAT_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 304 +#line 320 NPY_NO_EXPORT void CFLOAT_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2027,36 +2195,36 @@ CFLOAT_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func) NPY_NO_EXPORT void CFLOAT_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CFLOAT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CFLOAT_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CFLOAT_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2066,15 +2234,15 @@ CFLOAT_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED( NPY_NO_EXPORT void CFLOAT_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CFLOAT_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CFLOAT_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CFLOAT_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2100,20 +2268,20 @@ CFLOAT__arg(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void CFLOAT_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CFLOAT_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CFLOAT_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CFLOAT_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CFLOAT_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2121,14 +2289,14 @@ CFLOAT_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); #define CFLOAT_true_divide CFLOAT_divide -#line 298 +#line 314 -#line 304 +#line 320 NPY_NO_EXPORT void CDOUBLE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 304 +#line 320 NPY_NO_EXPORT void CDOUBLE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2143,36 +2311,36 @@ CDOUBLE_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func NPY_NO_EXPORT void CDOUBLE_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CDOUBLE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CDOUBLE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CDOUBLE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2182,15 +2350,15 @@ CDOUBLE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED NPY_NO_EXPORT void CDOUBLE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CDOUBLE_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CDOUBLE_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CDOUBLE_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2216,20 +2384,20 @@ CDOUBLE__arg(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) NPY_NO_EXPORT void CDOUBLE_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CDOUBLE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CDOUBLE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CDOUBLE_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CDOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2237,14 +2405,14 @@ CDOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) #define CDOUBLE_true_divide CDOUBLE_divide -#line 298 +#line 314 -#line 304 +#line 320 NPY_NO_EXPORT void CLONGDOUBLE_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 304 +#line 320 NPY_NO_EXPORT void CLONGDOUBLE_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2259,36 +2427,36 @@ CLONGDOUBLE_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED( NPY_NO_EXPORT void CLONGDOUBLE_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 322 +#line 338 NPY_NO_EXPORT void CLONGDOUBLE_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CLONGDOUBLE_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 331 +#line 347 NPY_NO_EXPORT void CLONGDOUBLE_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2298,15 +2466,15 @@ CLONGDOUBLE_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UN NPY_NO_EXPORT void CLONGDOUBLE_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CLONGDOUBLE_isnan(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CLONGDOUBLE_isinf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 345 +#line 361 NPY_NO_EXPORT void CLONGDOUBLE_isfinite(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2332,20 +2500,20 @@ CLONGDOUBLE__arg(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu NPY_NO_EXPORT void CLONGDOUBLE_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CLONGDOUBLE_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 374 +#line 390 NPY_NO_EXPORT void CLONGDOUBLE_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CLONGDOUBLE_fmax(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 382 +#line 398 NPY_NO_EXPORT void CLONGDOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2367,121 +2535,121 @@ CLONGDOUBLE_fmin(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu ***************************************************************************** */ -#line 406 +#line 422 #define DATETIME_fmax DATETIME_maximum #define DATETIME_fmin DATETIME_minimum -#line 406 +#line 422 #define TIMEDELTA_fmax TIMEDELTA_maximum #define TIMEDELTA_fmin TIMEDELTA_minimum -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_logical_and(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_logical_or(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_maximum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_minimum(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void TIMEDELTA_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 415 +#line 431 NPY_NO_EXPORT void DATETIME_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); @@ -2513,27 +2681,27 @@ TIMEDELTA_mm_m_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UN ***************************************************************************** */ -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 450 +#line 466 NPY_NO_EXPORT void OBJECT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index 33dfe882e..d4ec0a78d 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -3,6 +3,20 @@ * vim:syntax=c */ +/* + ***************************************************************************** + ** IMPORTANT NOTE for loops.h.src -> loops.h ** + ***************************************************************************** + * The template file loops.h.src is not automatically converted into + * loops.h by the build system. If you edit this file, you must manually + * do the conversion using numpy/distutils/conv_template.py from the + * command line as follows: + * + * $ cd <NumPy source root directory> + * $ python numpy/distutils/conv_template.py numpy/core/src/umath/loops.h.src + * $ + */ + #ifndef _NPY_UMATH_LOOPS_H_ #define _NPY_UMATH_LOOPS_H_ @@ -172,10 +186,10 @@ U@TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f /**begin repeat * Float types - * #type = float, double, longdouble# - * #TYPE = FLOAT, DOUBLE, LONGDOUBLE# - * #c = f, , l# - * #C = F, , L# + * #type = npy_half, float, double, longdouble# + * #TYPE = HALF, FLOAT, DOUBLE, LONGDOUBLE# + * #c = f, f, , l# + * #C = F, F, , L# */ diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index be38a9f10..39b04db73 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -224,10 +224,11 @@ _lowest_type(char intype) case PyArray_ULONG: case PyArray_ULONGLONG: return PyArray_UBYTE; - /* case PyArray_FLOAT:*/ + /* case PyArray_HALF: */ + case PyArray_FLOAT: case PyArray_DOUBLE: case PyArray_LONGDOUBLE: - return PyArray_FLOAT; + return PyArray_HALF; /* case PyArray_CFLOAT:*/ case PyArray_CDOUBLE: case PyArray_CLONGDOUBLE: @@ -3328,7 +3329,7 @@ PyUFunc_GenericReduction(PyUFuncObject *self, PyObject *args, * is used for add and multiply reduction to avoid overflow */ int typenum = PyArray_TYPE(mp); - if ((typenum < NPY_FLOAT) + if ((typenum < NPY_HALF) && ((strcmp(self->name,"add") == 0) || (strcmp(self->name,"multiply") == 0))) { if (PyTypeNum_ISBOOL(typenum)) { diff --git a/numpy/core/src/umath/umathmodule.c.src b/numpy/core/src/umath/umathmodule.c.src index c3da9f3d3..7a76c2b3e 100644 --- a/numpy/core/src/umath/umathmodule.c.src +++ b/numpy/core/src/umath/umathmodule.c.src @@ -155,6 +155,7 @@ ufunc_frompyfunc(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *NPY_UNUS static PyUFuncGenericFunction frexp_functions[] = { #ifdef HAVE_FREXPF + HALF_frexp, FLOAT_frexp, #endif DOUBLE_frexp @@ -168,6 +169,7 @@ static void * blank6_data[] = { (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL}; static char frexp_signatures[] = { #ifdef HAVE_FREXPF + PyArray_HALF, PyArray_HALF, PyArray_INT, PyArray_FLOAT, PyArray_FLOAT, PyArray_INT, #endif PyArray_DOUBLE, PyArray_DOUBLE, PyArray_INT @@ -184,7 +186,9 @@ static char frexp_signatures[] = { static PyUFuncGenericFunction ldexp_functions[] = { #ifdef HAVE_LDEXPF + HALF_ldexp, FLOAT_ldexp, + LDEXP_LONG(HALF), LDEXP_LONG(FLOAT), #endif DOUBLE_ldexp, @@ -198,7 +202,9 @@ static PyUFuncGenericFunction ldexp_functions[] = { static char ldexp_signatures[] = { #ifdef HAVE_LDEXPF + PyArray_HALF, PyArray_INT, PyArray_HALF, PyArray_FLOAT, PyArray_INT, PyArray_FLOAT, + PyArray_HALF, PyArray_LONG, PyArray_HALF, PyArray_FLOAT, PyArray_LONG, PyArray_FLOAT, #endif PyArray_DOUBLE, PyArray_INT, PyArray_DOUBLE, @@ -212,14 +218,9 @@ static char ldexp_signatures[] = { static void InitOtherOperators(PyObject *dictionary) { PyObject *f; - int num=1; + int num; -#ifdef HAVE_FREXPL - num += 1; -#endif -#ifdef HAVE_FREXPF - num += 1; -#endif + num = sizeof(frexp_functions) / sizeof(frexp_functions[0]); f = PyUFunc_FromFuncAndData(frexp_functions, blank3_data, frexp_signatures, num, 1, 2, PyUFunc_None, "frexp", @@ -228,13 +229,7 @@ InitOtherOperators(PyObject *dictionary) { PyDict_SetItemString(dictionary, "frexp", f); Py_DECREF(f); - num = 2; -#ifdef HAVE_LDEXPL - num += 2; -#endif -#ifdef HAVE_LDEXPF - num += 2; -#endif + num = sizeof(ldexp_functions) / sizeof(ldexp_functions[0]); f = PyUFunc_FromFuncAndData(ldexp_functions, blank6_data, ldexp_signatures, num, 2, 1, PyUFunc_None, "ldexp", "Compute y = x1 * 2**x2.",0); diff --git a/numpy/core/tests/test_getlimits.py b/numpy/core/tests/test_getlimits.py index f52463cbb..569dc0cc6 100644 --- a/numpy/core/tests/test_getlimits.py +++ b/numpy/core/tests/test_getlimits.py @@ -4,7 +4,7 @@ from numpy.testing import * from numpy.core import finfo, iinfo -from numpy import single,double,longdouble +from numpy import half, single, double, longdouble import numpy as np ################################################## @@ -15,6 +15,12 @@ class TestPythonFloat(TestCase): ftype2 = finfo(float) assert_equal(id(ftype),id(ftype2)) +class TestHalf(TestCase): + def test_singleton(self): + ftype = finfo(half) + ftype2 = finfo(half) + assert_equal(id(ftype),id(ftype2)) + class TestSingle(TestCase): def test_singleton(self): ftype = finfo(single) diff --git a/numpy/core/tests/test_half.py b/numpy/core/tests/test_half.py new file mode 100644 index 000000000..409e50e92 --- /dev/null +++ b/numpy/core/tests/test_half.py @@ -0,0 +1,421 @@ +import numpy as np +from numpy import uint16, float16, float32, float64 +from numpy.testing import * + +import warnings + +def assert_raises_fpe(strmatch, callable, *args, **kwargs): + try: + callable(*args, **kwargs) + except FloatingPointError, exc: + assert_(str(exc).find(strmatch) >= 0, + "Did not raise floating point %s error" % strmatch) + else: + assert_(False, + "Did not raise floating point %s error" % strmatch) + +class TestHalf(TestCase): + def setUp(self): + # An array of all possible float16 values + self.all_f16 = np.arange(0x10000, dtype=uint16) + self.all_f16.dtype = float16 + self.all_f32 = np.array(self.all_f16, dtype=float32) + self.all_f64 = np.array(self.all_f16, dtype=float64) + + # An array of all non-NaN float16 values, in sorted order + self.nonan_f16 = np.concatenate( + (np.arange(0xfc00,0x7fff,-1, dtype=uint16), + np.arange(0x0000,0x7c01,1, dtype=uint16)) + ) + self.nonan_f16.dtype = float16 + self.nonan_f32 = np.array(self.nonan_f16, dtype=float32) + self.nonan_f64 = np.array(self.nonan_f16, dtype=float64) + + # An array of all finite float16 values, in sorted order + self.finite_f16 = self.nonan_f16[1:-1] + self.finite_f32 = self.nonan_f32[1:-1] + self.finite_f64 = self.nonan_f64[1:-1] + + def test_half_conversions(self): + """Checks that all 16-bit values survive conversion + to/from 32-bit and 64-bit float""" + # Because the underlying routines preserve the NaN bits, every + # value is preserved when converting to/from other floats. + + # Convert from float32 back to float16 + b = np.array(self.all_f32, dtype=float16) + assert_equal(self.all_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Convert from float64 back to float16 + b = np.array(self.all_f64, dtype=float16) + assert_equal(self.all_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Convert float16 to longdouble and back + # This doesn't necessarily preserve the extra NaN bits, + # so exclude NaNs. + a_ld = np.array(self.nonan_f16, dtype=np.longdouble) + b = np.array(a_ld, dtype=float16) + assert_equal(self.nonan_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Check the range for which all integers can be represented + i_int = np.arange(-2048,2049) + i_f16 = np.array(i_int, dtype=float16) + j = np.array(i_f16, dtype=np.int) + assert_equal(i_int,j) + + def test_nans_infs(self): + # Check some of the ufuncs + assert_equal(np.isnan(self.all_f16), np.isnan(self.all_f32)) + assert_equal(np.isinf(self.all_f16), np.isinf(self.all_f32)) + assert_equal(np.isfinite(self.all_f16), np.isfinite(self.all_f32)) + assert_equal(np.signbit(self.all_f16), np.signbit(self.all_f32)) + + # Check comparisons of all values with NaN + nan = float16(np.nan) + + assert_(not (self.all_f16 == nan).any()) + assert_(not (nan == self.all_f16).any()) + + assert_((self.all_f16 != nan).all()) + assert_((nan != self.all_f16).all()) + + assert_(not (self.all_f16 < nan).any()) + assert_(not (nan < self.all_f16).any()) + + assert_(not (self.all_f16 <= nan).any()) + assert_(not (nan <= self.all_f16).any()) + + assert_(not (self.all_f16 > nan).any()) + assert_(not (nan > self.all_f16).any()) + + assert_(not (self.all_f16 >= nan).any()) + assert_(not (nan >= self.all_f16).any()) + + + def test_half_values(self): + """Confirms a small number of known half values""" + a = np.array([1.0, -1.0, + 2.0, -2.0, + 0.0999755859375, 0.333251953125, # 1/10, 1/3 + 65504, -65504, # Maximum magnitude + 2.0**(-14), -2.0**(-14), # Minimum normal + 2.0**(-24), -2.0**(-24), # Minimum subnormal + 0, -1/1e1000, # Signed zeros + np.inf, -np.inf]) + b = np.array([0x3c00, 0xbc00, + 0x4000, 0xc000, + 0x2e66, 0x3555, + 0x7bff, 0xfbff, + 0x0400, 0x8400, + 0x0001, 0x8001, + 0x0000, 0x8000, + 0x7c00, 0xfc00], dtype=uint16) + b.dtype = float16 + assert_equal(a, b) + + def test_half_rounding(self): + """Checks that rounding when converting to half is correct""" + a = np.array([2.0**-25 + 2.0**-35, # Rounds to minimum subnormal + 2.0**-25, # Underflows to zero (nearest even mode) + 2.0**-26, # Underflows to zero + 1.0+2.0**-11 + 2.0**-16, # rounds to 1.0+2**(-10) + 1.0+2.0**-11, # rounds to 1.0 (nearest even mode) + 1.0+2.0**-12, # rounds to 1.0 + 65519, # rounds to 65504 + 65520], # rounds to inf + dtype=float64) + rounded = [2.0**-24, + 0.0, + 0.0, + 1.0+2.0**(-10), + 1.0, + 1.0, + 65504, + np.inf] + + # Check float64->float16 rounding + b = np.array(a, dtype=float16) + assert_equal(b, rounded) + + # Check float32->float16 rounding + a = np.array(a, dtype=float32) + b = np.array(a, dtype=float16) + assert_equal(b, rounded) + + def test_half_correctness(self): + """Take every finite float16, and check the casting functions with + a manual conversion.""" + + # Create an array of all finite float16s + a_f16 = self.finite_f16 + a_bits = a_f16.view(dtype=uint16) + + # Convert to 64-bit float manually + a_sgn = (-1.0)**((a_bits&0x8000) >> 15) + a_exp = np.array((a_bits&0x7c00) >> 10, dtype=np.int32) - 15 + a_man = (a_bits&0x03ff) * 2.0**(-10) + # Implicit bit of normalized floats + a_man[a_exp!=-15] += 1 + # Denormalized exponent is -14 + a_exp[a_exp==-15] = -14 + + a_manual = a_sgn * a_man * 2.0**a_exp + + a32_fail = np.nonzero(self.finite_f32 != a_manual)[0] + if len(a32_fail) != 0: + bad_index = a32_fail[0] + assert_equal(self.finite_f32, a_manual, + "First non-equal is half value %x -> %g != %g" % + (a[bad_index], + self.finite_f32[bad_index], + a_manual[bad_index])) + + a64_fail = np.nonzero(self.finite_f64 != a_manual)[0] + if len(a64_fail) != 0: + bad_index = a64_fail[0] + assert_equal(self.finite_f64, a_manual, + "First non-equal is half value %x -> %g != %g" % + (a[bad_index], + self.finite_f64[bad_index], + a_manual[bad_index])) + + def test_half_ordering(self): + """Make sure comparisons are working right""" + + # All non-NaN float16 values in reverse order + a = self.nonan_f16[::-1].copy() + + # 32-bit float copy + b = np.array(a, dtype=float32) + + # Should sort the same + a.sort() + b.sort() + assert_equal(a, b) + + # Comparisons should work + assert_((a[:-1] <= a[1:]).all()) + assert_(not (a[:-1] > a[1:]).any()) + assert_((a[1:] >= a[:-1]).all()) + assert_(not (a[1:] < a[:-1]).any()) + # All != except for +/-0 + assert_equal(np.nonzero(a[:-1] < a[1:])[0].size, a.size-2) + assert_equal(np.nonzero(a[1:] > a[:-1])[0].size, a.size-2) + + def test_half_funcs(self): + """Test the various ArrFuncs""" + + # fill + assert_equal(np.arange(10, dtype=float16), + np.arange(10, dtype=float32)) + + # fillwithscalar + a = np.zeros((5,), dtype=float16) + a.fill(1) + assert_equal(a, np.ones((5,), dtype=float16)) + + # nonzero and copyswap + a = np.array([0,0,-1,-1/1e20,0,2.0**-24, 7.629e-6], dtype=float16) + assert_equal(a.nonzero()[0], + [2,5,6]) + a = a.byteswap().newbyteorder() + assert_equal(a.nonzero()[0], + [2,5,6]) + + # dot + a = np.arange(0, 10, 0.5, dtype=float16) + b = np.ones((20,), dtype=float16) + assert_equal(np.dot(a,b), + 95) + + # argmax + a = np.array([0, -np.inf, -2, 0.5, 12.55, 7.3, 2.1, 12.4], dtype=float16) + assert_equal(a.argmax(), + 4) + a = np.array([0, -np.inf, -2, np.inf, 12.55, np.nan, 2.1, 12.4], dtype=float16) + assert_equal(a.argmax(), + 5) + + # getitem + a = np.arange(10, dtype=float16) + for i in range(10): + assert_equal(a.item(i),i) + + def test_spacing_nextafter(self): + """Test np.spacing and np.nextafter""" + # All non-negative finite #'s + a = np.arange(0x7c00, dtype=uint16) + hinf = np.array((np.inf,), dtype=float16) + a_f16 = a.view(dtype=float16) + + assert_equal(np.spacing(a_f16[:-1]), a_f16[1:]-a_f16[:-1]) + + assert_equal(np.nextafter(a_f16[:-1], hinf), a_f16[1:]) + assert_equal(np.nextafter(a_f16[0], -hinf), -a_f16[1]) + assert_equal(np.nextafter(a_f16[1:], -hinf), a_f16[:-1]) + + # switch to negatives + a |= 0x8000 + + assert_equal(np.spacing(a_f16[0]), np.spacing(a_f16[1])) + assert_equal(np.spacing(a_f16[1:]), a_f16[:-1]-a_f16[1:]) + + assert_equal(np.nextafter(a_f16[0], hinf), -a_f16[1]) + assert_equal(np.nextafter(a_f16[1:], hinf), a_f16[:-1]) + assert_equal(np.nextafter(a_f16[:-1], -hinf), a_f16[1:]) + + + def test_half_ufuncs(self): + """Test the various ufuncs""" + + a = np.array([0,1,2,4,2], dtype=float16) + b = np.array([-2,5,1,4,3], dtype=float16) + c = np.array([0,-1,-np.inf,np.nan,6], dtype=float16) + + assert_equal(np.add(a,b), [-2,6,3,8,5]) + assert_equal(np.subtract(a,b), [2,-4,1,0,-1]) + assert_equal(np.multiply(a,b), [0,5,2,16,6]) + assert_equal(np.divide(a,b), [0,0.199951171875,2,1,0.66650390625]) + + assert_equal(np.equal(a,b), [False,False,False,True,False]) + assert_equal(np.not_equal(a,b), [True,True,True,False,True]) + assert_equal(np.less(a,b), [False,True,False,False,True]) + assert_equal(np.less_equal(a,b), [False,True,False,True,True]) + assert_equal(np.greater(a,b), [True,False,True,False,False]) + assert_equal(np.greater_equal(a,b), [True,False,True,True,False]) + assert_equal(np.logical_and(a,b), [False,True,True,True,True]) + assert_equal(np.logical_or(a,b), [True,True,True,True,True]) + assert_equal(np.logical_xor(a,b), [True,False,False,False,False]) + assert_equal(np.logical_not(a), [True,False,False,False,False]) + + assert_equal(np.isnan(c), [False,False,False,True,False]) + assert_equal(np.isinf(c), [False,False,True,False,False]) + assert_equal(np.isfinite(c), [True,True,False,False,True]) + assert_equal(np.signbit(b), [True,False,False,False,False]) + + assert_equal(np.copysign(b,a), [2,5,1,4,3]) + + assert_equal(np.maximum(a,b), [0,5,2,4,3]) + x = np.maximum(b,c) + assert_(np.isnan(x[3])) + x[3] = 0 + assert_equal(x, [0,5,1,0,6]) + assert_equal(np.minimum(a,b), [-2,1,1,4,2]) + x = np.minimum(b,c) + assert_(np.isnan(x[3])) + x[3] = 0 + assert_equal(x, [-2,-1,-np.inf,0,3]) + assert_equal(np.fmax(a,b), [0,5,2,4,3]) + assert_equal(np.fmax(b,c), [0,5,1,4,6]) + assert_equal(np.fmin(a,b), [-2,1,1,4,2]) + assert_equal(np.fmin(b,c), [-2,-1,-np.inf,4,3]) + + assert_equal(np.floor_divide(a,b), [0,0,2,1,0]) + assert_equal(np.remainder(a,b), [0,1,0,0,2]) + assert_equal(np.square(b), [4,25,1,16,9]) + assert_equal(np.reciprocal(b), [-0.5,0.199951171875,1,0.25,0.333251953125]) + assert_equal(np.ones_like(b), [1,1,1,1,1]) + assert_equal(np.conjugate(b), b) + assert_equal(np.absolute(b), [2,5,1,4,3]) + assert_equal(np.negative(b), [2,-5,-1,-4,-3]) + assert_equal(np.sign(b), [-1,1,1,1,1]) + assert_equal(np.modf(b), ([0,0,0,0,0],b)) + assert_equal(np.frexp(b), ([-0.5,0.625,0.5,0.5,0.75],[2,3,1,3,2])) + assert_equal(np.ldexp(b,[0,1,2,4,2]), [-2,10,4,64,12]) + + def test_half_coercion(self): + """Test that half gets coerced properly with the other types""" + a16 = np.array((1,),dtype=float16) + a32 = np.array((1,),dtype=float32) + b16 = float16(1) + b32 = float32(1) + + assert_equal(np.power(a16,2).dtype, float16) + assert_equal(np.power(a16,2.0).dtype, float16) + assert_equal(np.power(a16,b16).dtype, float16) + assert_equal(np.power(a16,b32).dtype, float16) + assert_equal(np.power(a16,a16).dtype, float16) + assert_equal(np.power(a16,a32).dtype, float32) + + assert_equal(np.power(b16,2).dtype, float64) + assert_equal(np.power(b16,2.0).dtype, float64) + assert_equal(np.power(b16,b16).dtype, float16) + assert_equal(np.power(b16,b32).dtype, float32) + assert_equal(np.power(b16,a16).dtype, float16) + assert_equal(np.power(b16,a32).dtype, float32) + + assert_equal(np.power(a32,a16).dtype, float32) + assert_equal(np.power(a32,b16).dtype, float32) + assert_equal(np.power(b32,a16).dtype, float16) + assert_equal(np.power(b32,b16).dtype, float32) + + def test_half_fpe(self): + """Test that half raises the correct underflows and overflows""" + oldsettings = np.seterr(all='raise') + try: + sx16 = np.array((1e-4,),dtype=float16) + bx16 = np.array((1e4,),dtype=float16) + sy16 = float16(1e-4) + by16 = float16(1e4) + + # Underflow errors + assert_raises_fpe('underflow', lambda a,b:a*b, sx16, sx16) + assert_raises_fpe('underflow', lambda a,b:a*b, sx16, sy16) + assert_raises_fpe('underflow', lambda a,b:a*b, sy16, sx16) + assert_raises_fpe('underflow', lambda a,b:a*b, sy16, sy16) + assert_raises_fpe('underflow', lambda a,b:a/b, sx16, bx16) + assert_raises_fpe('underflow', lambda a,b:a/b, sx16, by16) + assert_raises_fpe('underflow', lambda a,b:a/b, sy16, bx16) + assert_raises_fpe('underflow', lambda a,b:a/b, sy16, by16) + assert_raises_fpe('underflow', lambda a,b:a/b, + float16(2.**-14), float16(2**11)) + assert_raises_fpe('underflow', lambda a,b:a/b, + float16(-2.**-14), float16(2**11)) + assert_raises_fpe('underflow', lambda a,b:a/b, + float16(2.**-14+2**-24), float16(2)) + assert_raises_fpe('underflow', lambda a,b:a/b, + float16(-2.**-14-2**-24), float16(2)) + assert_raises_fpe('underflow', lambda a,b:a/b, + float16(2.**-14+2**-23), float16(4)) + + # Overflow errors + assert_raises_fpe('overflow', lambda a,b:a*b, bx16, bx16) + assert_raises_fpe('overflow', lambda a,b:a*b, bx16, by16) + assert_raises_fpe('overflow', lambda a,b:a*b, by16, bx16) + assert_raises_fpe('overflow', lambda a,b:a*b, by16, by16) + assert_raises_fpe('overflow', lambda a,b:a/b, bx16, sx16) + assert_raises_fpe('overflow', lambda a,b:a/b, bx16, sy16) + assert_raises_fpe('overflow', lambda a,b:a/b, by16, sx16) + assert_raises_fpe('overflow', lambda a,b:a/b, by16, sy16) + assert_raises_fpe('overflow', lambda a,b:a+b, + float16(65504), float16(17)) + assert_raises_fpe('overflow', lambda a,b:a-b, + float16(-65504), float16(17)) + assert_raises_fpe('overflow', np.nextafter, float16(65504), float16(np.inf)) + assert_raises_fpe('overflow', np.nextafter, float16(-65504), float16(-np.inf)) + + # Invalid value errors + assert_raises_fpe('invalid', np.divide, float16(np.inf), float16(np.inf)) + assert_raises_fpe('invalid', np.spacing, float16(65504)) + assert_raises_fpe('invalid', np.spacing, float16(np.inf)) + assert_raises_fpe('invalid', np.spacing, float16(np.nan)) + assert_raises_fpe('invalid', np.nextafter, float16(np.inf), float16(0)) + assert_raises_fpe('invalid', np.nextafter, float16(-np.inf), float16(0)) + assert_raises_fpe('invalid', np.nextafter, float16(0), float16(np.nan)) + + # These should not raise + float16(65472)+float16(32) + float16(2**-13)/float16(2) + float16(2**-14)/float16(2**10) + np.spacing(float16(-65504)) + np.nextafter(float16(65504), float16(-np.inf)) + np.nextafter(float16(-65504), float16(np.inf)) + float16(2**-14)/float16(2**10) + float16(-2**-14)/float16(2**10) + float16(2**-14+2**-23)/float16(2) + float16(-2**-14-2**-23)/float16(2) + finally: + np.seterr(**oldsettings) diff --git a/numpy/doc/basics.py b/numpy/doc/basics.py index ea651bbc7..97e982204 100644 --- a/numpy/doc/basics.py +++ b/numpy/doc/basics.py @@ -23,6 +23,8 @@ uint16 Unsigned integer (0 to 65535) uint32 Unsigned integer (0 to 4294967295) uint64 Unsigned integer (0 to 18446744073709551615) float Shorthand for ``float64``. +float16 Half precision float: sign bit, 5 bits exponent, + 10 bits mantissa float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa float64 Double precision float: sign bit, 11 bits exponent, diff --git a/numpy/doc/structured_arrays.py b/numpy/doc/structured_arrays.py index 21fdf87ea..6eafd71cd 100644 --- a/numpy/doc/structured_arrays.py +++ b/numpy/doc/structured_arrays.py @@ -70,10 +70,10 @@ In this case, the constructor expects a comma-separated list of type specifiers, optionally with extra shape information. The type specifiers can take 4 different forms: :: - a) b1, i1, i2, i4, i8, u1, u2, u4, u8, f4, f8, c8, c16, a<n> + a) b1, i1, i2, i4, i8, u1, u2, u4, u8, f2, f4, f8, c8, c16, a<n> (representing bytes, ints, unsigned ints, floats, complex and fixed length strings of specified byte lengths) - b) int8,...,uint8,...,float32, float64, complex64, complex128 + b) int8,...,uint8,...,float16, float32, float64, complex64, complex128 (this time with bit sizes) c) older Numeric/numarray type specifications (e.g. Float32). Don't use these in new code! |