Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
('c:type', '__int64'),
('c:type', 'unsigned __int64'),
('c:type', 'double'),
('c:type', '_Float16'),
# Standard C structures
('c:struct', 'in6_addr'),
('c:struct', 'in_addr'),
Expand Down
17 changes: 15 additions & 2 deletions Doc/library/array.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ defined:
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'Q'`` | unsigned long long | int | 8 | |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'e'`` | _Float16 | float | 2 | \(3) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'f'`` | float | float | 4 | |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'d'`` | double | float | 8 | |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'F'`` | float complex | complex | 8 | \(3) |
| ``'F'`` | float complex | complex | 8 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'D'`` | double complex | complex | 16 | \(3) |
| ``'D'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+


Expand All @@ -69,6 +71,15 @@ Notes:
.. versionadded:: 3.13

(3)
The IEEE 754 binary16 "half precision" type was introduced in the 2008
revision of the `IEEE 754 standard <ieee 754 standard_>`_.
This type is not widely supported by C compilers. It's available
as :c:expr:`_Float16` type, if the compiler supports the Annex H
of the C23 standard.

.. versionadded:: 3.15
Comment thread
skirpichev marked this conversation as resolved.
Outdated

(4)
Complex types (``F`` and ``D``) are available unconditionally,
regardless on support for complex types (the Annex G of the C11 standard)
by the C compiler.
Expand Down Expand Up @@ -304,3 +315,5 @@ Examples::

`NumPy <https://numpy.org/>`_
The NumPy package defines another array type.

.. _ieee 754 standard: https://en.wikipedia.org/wiki/IEEE_754-2008_revision
7 changes: 4 additions & 3 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -637,9 +637,10 @@ argparse
array
-----

* Support the :c:expr:`float complex` and :c:expr:`double complex` C types:
formatting characters ``'F'`` and ``'D'`` respectively.
(Contributed by Sergey B Kirpichev in :gh:`146151`.)
* Support half-floats (16-bit IEEE 754 binary interchange format, formatting
character ``'e'``), the :c:expr:`float complex` and :c:expr:`double complex`
C types (formatting characters ``'F'`` and ``'D'`` respectively).
(Contributed by Sergey B Kirpichev in :gh:`146151` and :gh:`146238`.)
Comment thread
skirpichev marked this conversation as resolved.
Outdated
Comment thread
skirpichev marked this conversation as resolved.
Outdated


base64
Expand Down
13 changes: 11 additions & 2 deletions Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ArraySubclassWithKwargs(array.array):
def __init__(self, typecode, newarg=None):
array.array.__init__(self)

typecodes = 'uwbBhHiIlLfdqQFD'
typecodes = 'uwbBhHiIlLfdqQFDe'

class MiscTest(unittest.TestCase):

Expand Down Expand Up @@ -117,8 +117,10 @@ def __index__(self):
IEEE_754_FLOAT_COMPLEX_BE = 23
IEEE_754_DOUBLE_COMPLEX_LE = 24
IEEE_754_DOUBLE_COMPLEX_BE = 25
IEEE_754_FLOAT16_LE = 26
IEEE_754_FLOAT16_BE = 27

MACHINE_FORMAT_CODE_MAX = 25
MACHINE_FORMAT_CODE_MAX = 27


class ArrayReconstructorTest(unittest.TestCase):
Expand Down Expand Up @@ -1588,6 +1590,13 @@ def test_byteswap(self):
self.assertEqual(a, b)


class HalfFloatTest(FPTest, unittest.TestCase):
example = [-42.0, 0, 42, 1e3, -1e3]
smallerexample = [-42.0, 0, 42, 1e3, -2e3]
biggerexample = [-42.0, 0, 42, 1e3, 1e3]
Comment thread
vstinner marked this conversation as resolved.
Outdated
typecode = 'e'
minitemsize = 2

class FloatTest(FPTest, unittest.TestCase):
typecode = 'f'
minitemsize = 4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Support half-floats (type code ``'e'`` of the :mod:`struct` module) in the
:mod:`array` module. Patch by Sergey B Kirpichev.
60 changes: 58 additions & 2 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,12 @@ enum machine_format_code {
IEEE_754_FLOAT_COMPLEX_LE = 22,
IEEE_754_FLOAT_COMPLEX_BE = 23,
IEEE_754_DOUBLE_COMPLEX_LE = 24,
IEEE_754_DOUBLE_COMPLEX_BE = 25
IEEE_754_DOUBLE_COMPLEX_BE = 25,
IEEE_754_FLOAT16_LE = 26,
IEEE_754_FLOAT16_BE = 27
};
#define MACHINE_FORMAT_CODE_MIN 0
#define MACHINE_FORMAT_CODE_MAX 25
#define MACHINE_FORMAT_CODE_MAX 27


/*
Expand Down Expand Up @@ -611,6 +613,32 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
return 0;
}

static PyObject *
e_getitem(arrayobject *ap, Py_ssize_t i)
{
double x = PyFloat_Unpack2(ap->ob_item + sizeof(short)*i,
PY_LITTLE_ENDIAN);

return PyFloat_FromDouble(x);
}

static int
e_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
float x;
if (!PyArg_Parse(v, "f;array item must be float", &x)) {
return -1;
}

CHECK_ARRAY_BOUNDS(ap, i);

if (i >= 0) {
return PyFloat_Pack2(x, ap->ob_item + sizeof(short)*i,
PY_LITTLE_ENDIAN);
}
return 0;
}

static PyObject *
f_getitem(arrayobject *ap, Py_ssize_t i)
{
Expand Down Expand Up @@ -751,6 +779,7 @@ static const struct arraydescr descriptors[] = {
{'L', sizeof(long), LL_getitem, LL_setitem, LL_compareitems, "L", 1, 0},
{'q', sizeof(long long), q_getitem, q_setitem, q_compareitems, "q", 1, 1},
{'Q', sizeof(long long), QQ_getitem, QQ_setitem, QQ_compareitems, "Q", 1, 0},
{'e', sizeof(short), e_getitem, e_setitem, NULL, "e", 0, 0},
{'f', sizeof(float), f_getitem, f_setitem, NULL, "f", 0, 0},
{'d', sizeof(double), d_getitem, d_setitem, NULL, "d", 0, 0},
{'F', 2*sizeof(float), cf_getitem, cf_setitem, NULL, "F", 0, 0},
Expand Down Expand Up @@ -2090,6 +2119,8 @@ static const struct mformatdescr {
{8, 0, 1}, /* 23: IEEE_754_FLOAT_COMPLEX_BE */
{16, 0, 0}, /* 24: IEEE_754_DOUBLE_COMPLEX_LE */
{16, 0, 1}, /* 25: IEEE_754_DOUBLE_COMPLEX_BE */
{2, 0, 0}, /* 26: IEEE_754_FLOAT16_LE */
{2, 0, 1} /* 27: IEEE_754_FLOAT16_BE */
};


Expand Down Expand Up @@ -2124,6 +2155,9 @@ typecode_to_mformat_code(char typecode)
case 'w':
return UTF32_LE + is_big_endian;

case 'e':
return _PY_FLOAT_BIG_ENDIAN ? IEEE_754_FLOAT16_BE : IEEE_754_FLOAT16_LE;

case 'f':
return _PY_FLOAT_BIG_ENDIAN ? IEEE_754_FLOAT_BE : IEEE_754_FLOAT_LE;

Expand Down Expand Up @@ -2309,6 +2343,27 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
return NULL;
}
switch (mformat_code) {
case IEEE_754_FLOAT16_LE:
case IEEE_754_FLOAT16_BE: {
Py_ssize_t i;
int le = (mformat_code == IEEE_754_FLOAT_LE) ? 1 : 0;
Py_ssize_t itemcount = Py_SIZE(items) / 2;
const char *memstr = PyBytes_AS_STRING(items);

converted_items = PyList_New(itemcount);
if (converted_items == NULL)
return NULL;
for (i = 0; i < itemcount; i++) {
PyObject *pyfloat = PyFloat_FromDouble(
PyFloat_Unpack2(&memstr[i * 2], le));
if (pyfloat == NULL) {
Py_DECREF(converted_items);
return NULL;
}
PyList_SET_ITEM(converted_items, i, pyfloat);
}
break;
}
case IEEE_754_FLOAT_LE:
case IEEE_754_FLOAT_BE: {
Py_ssize_t i;
Expand Down Expand Up @@ -3129,6 +3184,7 @@ The following type codes are defined:\n\
'L' unsigned integer 4\n\
'q' signed integer 8 (see note)\n\
'Q' unsigned integer 8 (see note)\n\
'e' 16-bit IEEE floats 2\n\
'f' floating-point 4\n\
'd' floating-point 8\n\
'F' float complex 8\n\
Expand Down
Loading