cpython: 519bde9db8e0 (original) (raw)

Mercurial > cpython

changeset 103022:519bde9db8e0

Issue #11734: Add support for IEEE 754 half-precision floats to the struct module. Original patch by Eli Stevens. [#11734]

Mark Dickinson dickinsm@gmail.com
date Sat, 03 Sep 2016 17:21:29 +0100
parents 85f9f8bf2ec8
children fd4e4fa75260
files Doc/library/struct.rst Include/floatobject.h Lib/test/test_struct.py Misc/ACKS Misc/NEWS Modules/_struct.c Objects/floatobject.c
diffstat 7 files changed, 393 insertions(+), 11 deletions(-)[+] [-] Doc/library/struct.rst 23 Include/floatobject.h 10 Lib/test/test_struct.py 107 Misc/ACKS 1 Misc/NEWS 3 Modules/_struct.c 76 Objects/floatobject.c 184

line wrap: on

line diff

--- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -216,6 +216,8 @@ platform-dependent. +--------+--------------------------+--------------------+----------------+------------+ | N | :c:type:size_t | integer | | (4) | +--------+--------------------------+--------------------+----------------+------------+ +| e | (7) | float | 2 | (5) | ++--------+--------------------------+--------------------+----------------+------------+ | f | :c:type:float | float | 4 | (5) | +--------+--------------------------+--------------------+----------------+------------+ | d | :c:type:double | float | 8 | (5) | @@ -257,9 +259,10 @@ Notes: fits your application. (5)

(6) The 'P' format character is only available for the native byte ordering @@ -268,6 +271,16 @@ Notes: on the host system. The struct module does not interpret this as native ordering, so the 'P' format is not available. +(7)

A format character may be preceded by an integral repeat count. For example, the format string '4h' means exactly the same as 'hhhh'. @@ -430,3 +443,7 @@ The :mod:struct module also defines th The calculated size of the struct (and hence of the bytes object produced by the :meth:pack method) corresponding to :attr:format. + +.. _half precision format: https://en.wikipedia.org/wiki/Half-precision_floating-point_format[](#l1.48) + +.. _ieee 754 standard: https://en.wikipedia.org/wiki/IEEE_floating_point#IEEE_754-2008[](#l1.50)

--- a/Include/floatobject.h +++ b/Include/floatobject.h @@ -74,9 +74,9 @@ PyAPI_FUNC(double) PyFloat_AsDouble(PyOb

-/* The pack routines write 4 or 8 bytes, starting at p. le is a bool +/* The pack routines write 2, 4 or 8 bytes, starting at p. le is a bool

--- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -1,5 +1,6 @@ from collections import abc import array +import math import operator import unittest import struct @@ -366,8 +367,6 @@ class StructTest(unittest.TestCase): # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry # from the low-order discarded bits could propagate into the exponent # field, causing the result to be wrong by a factor of 2.

- for base in range(1, 33): # smaller <- largest representable float less than base. delta = 0.5 @@ -659,6 +658,110 @@ class UnpackIteratorTest(unittest.TestCa self.assertRaises(StopIteration, next, it) self.assertRaises(StopIteration, next, it)

+

+

+

+

+

+

+

+

+

+

+ if name == 'main': unittest.main()

--- a/Misc/ACKS +++ b/Misc/ACKS @@ -1435,6 +1435,7 @@ Greg Stein Marek Stepniowski Baruch Sterin Chris Stern +Eli Stevens Alex Stewart Victor Stinner Richard Stoakley

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,9 @@ Core and Builtins Library ------- +- Issue #11734: Add support for IEEE 754 half-precision floats to the

--- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -267,6 +267,33 @@ get_size_t(PyObject *v, size_t p) / Floating point helpers */ static PyObject * +unpack_halffloat(const char p, / start of 2-byte string */

+{

+

+} + +static int +pack_halffloat(char p, / start of 2-byte string */

+{

+} + +static PyObject * unpack_float(const char p, / start of 4-byte string / int le) / true for little-endian, false for big-endian */ { @@ -470,6 +497,16 @@ nu_bool(const char *p, const formatdef * static PyObject * +nu_halffloat(const char *p, const formatdef *f) +{ +#if PY_LITTLE_ENDIAN

+#else

+#endif +} + +static PyObject * nu_float(const char *p, const formatdef *f) { float x; @@ -681,6 +718,16 @@ np_bool(char *p, PyObject *v, const form } static int +np_halffloat(char *p, PyObject *v, const formatdef *f) +{ +#if PY_LITTLE_ENDIAN

+#else

+#endif +} + +static int np_float(char *p, PyObject *v, const formatdef *f) { float x = (float)PyFloat_AsDouble(v); @@ -743,6 +790,7 @@ static const formatdef native_table[] = {'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong}, #endif {'?', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool},

static PyObject * +bu_halffloat(const char *p, const formatdef *f) +{

+} + +static PyObject * bu_float(const char *p, const formatdef *f) { return unpack_float(p, 0); @@ -922,6 +976,12 @@ bp_ulonglong(char *p, PyObject *v, const } static int +bp_halffloat(char *p, PyObject *v, const formatdef *f) +{

+} + +static int bp_float(char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); @@ -972,6 +1032,7 @@ static formatdef bigendian_table[] = { {'q', 8, 0, bu_longlong, bp_longlong}, {'Q', 8, 0, bu_ulonglong, bp_ulonglong}, {'?', 1, 0, bu_bool, bp_bool},

static PyObject * +lu_halffloat(const char *p, const formatdef *f) +{

+} + +static PyObject * lu_float(const char *p, const formatdef *f) { return unpack_float(p, 1); @@ -1142,6 +1209,12 @@ lp_ulonglong(char *p, PyObject *v, const } static int +lp_halffloat(char *p, PyObject *v, const formatdef *f) +{

+} + +static int lp_float(char *p, PyObject *v, const formatdef f) { double x = PyFloat_AsDouble(v); @@ -1182,6 +1255,7 @@ static formatdef lilendian_table[] = { {'Q', 8, 0, lu_ulonglong, lp_ulonglong}, {'?', 1, 0, bu_bool, bp_bool}, / Std rep not endian dep, but potentially different from native rep -- reuse bx_bool funcs. */

--- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1975,8 +1975,120 @@ void /*----------------------------------------------------------------------------

+

+

+

+

+

+

+

+

+

+

+

+} + int _PyFloat_Pack4(double x, unsigned char *p, int le) { @@ -2212,6 +2324,76 @@ int } double +_PyFloat_Unpack2(const unsigned char *p, int le) +{

+

+

+

+

+#ifdef PY_NO_SHORT_FLOAT_REPR

+#ifdef Py_NAN

+#else

+#endif /* #ifdef Py_NAN */

+#else

+#endif /* #ifdef PY_NO_SHORT_FLOAT_REPR */

+

+

+

+

+} + +double _PyFloat_Unpack4(const unsigned char *p, int le) { if (float_format == unknown_format) {