Skip to content

Implement half dtype #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
2 changes: 1 addition & 1 deletion doc/source/reference/arrays.dtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
4 changes: 3 additions & 1 deletion doc/source/reference/arrays.scalars.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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?
Expand Down
201 changes: 199 additions & 2 deletions doc/source/reference/c-api.coremath.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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.

14 changes: 8 additions & 6 deletions doc/source/reference/c-api.dtype.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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**

Expand All @@ -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**

Expand Down
34 changes: 26 additions & 8 deletions doc/source/reference/c-api.ufunc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
Binary file modified doc/source/reference/figures/dtype-hierarchy.dia
Binary file not shown.
Binary file modified doc/source/reference/figures/dtype-hierarchy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading