mirror of
https://github.com/python/cpython.git
synced 2026-05-06 04:37:33 -04:00
gh-145633: Remove support for ancient ARM platforms with mixed-endian doubles (#145634)
* Drop DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 macro. * Use DOUBLE_IS_BIG/LITTLE_ENDIAN_IEEE754 to detect endianness of float/doubles. * Drop "unknown_format" code path in PyFloat_Pack/Unpack*(). Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
committed by
GitHub
parent
bdf6de8c3f
commit
dae85c4d93
@@ -224,11 +224,6 @@ endian processor, or ``0`` on little endian processor.
|
||||
Return value: ``0`` if all is OK, ``-1`` if error (and an exception is set,
|
||||
most likely :exc:`OverflowError`).
|
||||
|
||||
There are two problems on non-IEEE platforms:
|
||||
|
||||
* What this does is undefined if *x* is a NaN or infinity.
|
||||
* ``-0.0`` and ``+0.0`` produce the same bytes string.
|
||||
|
||||
.. c:function:: int PyFloat_Pack2(double x, char *p, int le)
|
||||
|
||||
Pack a C double as the IEEE 754 binary16 half-precision format.
|
||||
@@ -256,9 +251,6 @@ Return value: The unpacked double. On error, this is ``-1.0`` and
|
||||
:c:func:`PyErr_Occurred` is true (and an exception is set, most likely
|
||||
:exc:`OverflowError`).
|
||||
|
||||
Note that on a non-IEEE platform this will refuse to unpack a bytes string that
|
||||
represents a NaN or infinity.
|
||||
|
||||
.. c:function:: double PyFloat_Unpack2(const char *p, int le)
|
||||
|
||||
Unpack the IEEE 754 binary16 half-precision format as a C double.
|
||||
|
||||
@@ -12,7 +12,6 @@ extern "C" {
|
||||
|
||||
/* runtime lifecycle */
|
||||
|
||||
extern void _PyFloat_InitState(PyInterpreterState *);
|
||||
extern PyStatus _PyFloat_InitTypes(PyInterpreterState *);
|
||||
extern void _PyFloat_FiniType(PyInterpreterState *);
|
||||
|
||||
@@ -42,6 +41,15 @@ extern double _Py_parse_inf_or_nan(const char *p, char **endptr);
|
||||
|
||||
extern int _Py_convert_int_to_double(PyObject **v, double *dbl);
|
||||
|
||||
/* Should match endianness of the platform in most (all?) cases. */
|
||||
|
||||
#ifdef DOUBLE_IS_BIG_ENDIAN_IEEE754
|
||||
# define _PY_FLOAT_BIG_ENDIAN 1
|
||||
# define _PY_FLOAT_LITTLE_ENDIAN 0
|
||||
#else
|
||||
# define _PY_FLOAT_BIG_ENDIAN 0
|
||||
# define _PY_FLOAT_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -182,8 +182,7 @@ extern void _Py_set_387controlword(unsigned short);
|
||||
// (extended precision), and we don't know how to change
|
||||
// the rounding precision.
|
||||
#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \
|
||||
!defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \
|
||||
!defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
|
||||
!defined(DOUBLE_IS_BIG_ENDIAN_IEEE754)
|
||||
# define _PY_SHORT_FLOAT_REPR 0
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ extern "C" {
|
||||
#include "pycore_debug_offsets.h" // _Py_DebugOffsets_INIT()
|
||||
#include "pycore_dtoa.h" // _dtoa_state_INIT()
|
||||
#include "pycore_faulthandler.h" // _faulthandler_runtime_state_INIT
|
||||
#include "pycore_floatobject.h" // _py_float_format_unknown
|
||||
#include "pycore_floatobject.h" // _py_float_format_*
|
||||
#include "pycore_function.h"
|
||||
#include "pycore_hamt.h" // _PyHamt_BitmapNode_Type
|
||||
#include "pycore_import.h" // IMPORTS_INIT
|
||||
@@ -84,10 +84,6 @@ extern PyTypeObject _PyExc_MemoryError;
|
||||
.stoptheworld = { \
|
||||
.is_global = 1, \
|
||||
}, \
|
||||
.float_state = { \
|
||||
.float_format = _py_float_format_unknown, \
|
||||
.double_format = _py_float_format_unknown, \
|
||||
}, \
|
||||
.types = { \
|
||||
.next_version_tag = _Py_TYPE_VERSION_NEXT, \
|
||||
}, \
|
||||
@@ -233,4 +229,4 @@ extern PyTypeObject _PyExc_MemoryError;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !Py_INTERNAL_RUNTIME_INIT_H */
|
||||
#endif /* !Py_INTERNAL_RUNTIME_INIT_H */
|
||||
|
||||
@@ -35,17 +35,6 @@ struct _pymem_allocators {
|
||||
PyObjectArenaAllocator obj_arena;
|
||||
};
|
||||
|
||||
enum _py_float_format_type {
|
||||
_py_float_format_unknown,
|
||||
_py_float_format_ieee_big_endian,
|
||||
_py_float_format_ieee_little_endian,
|
||||
};
|
||||
|
||||
struct _Py_float_runtime_state {
|
||||
enum _py_float_format_type float_format;
|
||||
enum _py_float_format_type double_format;
|
||||
};
|
||||
|
||||
struct pyhash_runtime_state {
|
||||
struct {
|
||||
#ifndef MS_WINDOWS
|
||||
@@ -270,7 +259,6 @@ struct pyruntimestate {
|
||||
} audit_hooks;
|
||||
|
||||
struct _py_object_runtime_state object_state;
|
||||
struct _Py_float_runtime_state float_state;
|
||||
struct _Py_unicode_runtime_state unicode_state;
|
||||
struct _types_runtime_state types;
|
||||
struct _Py_time_runtime_state time;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#undef SIZEOF_UINTPTR_T
|
||||
#undef SIZEOF_PTHREAD_T
|
||||
#undef WORDS_BIGENDIAN
|
||||
#undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754
|
||||
#undef DOUBLE_IS_BIG_ENDIAN_IEEE754
|
||||
#undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754
|
||||
#undef HAVE_GCC_ASM_FOR_X87
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Remove support for ancient ARM platforms (ARMv4L and ARMv5L OABI boards),
|
||||
using mixed-endian representation
|
||||
for doubles. Patch by Sergey B Kirpichev.
|
||||
Generated
+2
-2
@@ -290,7 +290,7 @@ PyDoc_STRVAR(float___getformat____doc__,
|
||||
"\n"
|
||||
"It exists mainly to be used in Python\'s test suite.\n"
|
||||
"\n"
|
||||
"This function returns whichever of \'unknown\', \'IEEE, big-endian\' or \'IEEE,\n"
|
||||
"This function returns whichever of \'IEEE, big-endian\' or \'IEEE,\n"
|
||||
"little-endian\' best describes the format of floating-point numbers used by the\n"
|
||||
"C type named by typestr.");
|
||||
|
||||
@@ -353,4 +353,4 @@ float___format__(PyObject *self, PyObject *arg)
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=927035897ea3573f input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=f0b2af257213c8b0 input=a9049054013a1b77]*/
|
||||
|
||||
+113
-523
@@ -1666,15 +1666,6 @@ float___getnewargs___impl(PyObject *self)
|
||||
return Py_BuildValue("(d)", ((PyFloatObject *)self)->ob_fval);
|
||||
}
|
||||
|
||||
/* this is for the benefit of the pack/unpack routines below */
|
||||
typedef enum _py_float_format_type float_format_type;
|
||||
#define unknown_format _py_float_format_unknown
|
||||
#define ieee_big_endian_format _py_float_format_ieee_big_endian
|
||||
#define ieee_little_endian_format _py_float_format_ieee_little_endian
|
||||
|
||||
#define float_format (_PyRuntime.float_state.float_format)
|
||||
#define double_format (_PyRuntime.float_state.double_format)
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
@permit_long_docstring_body
|
||||
@@ -1689,45 +1680,25 @@ You probably don't want to use this function.
|
||||
|
||||
It exists mainly to be used in Python's test suite.
|
||||
|
||||
This function returns whichever of 'unknown', 'IEEE, big-endian' or 'IEEE,
|
||||
This function returns whichever of 'IEEE, big-endian' or 'IEEE,
|
||||
little-endian' best describes the format of floating-point numbers used by the
|
||||
C type named by typestr.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
float___getformat___impl(PyTypeObject *type, const char *typestr)
|
||||
/*[clinic end generated code: output=2bfb987228cc9628 input=d2735823bfe8e81e]*/
|
||||
/*[clinic end generated code: output=2bfb987228cc9628 input=0ae1ba35d192f704]*/
|
||||
{
|
||||
float_format_type r;
|
||||
|
||||
if (strcmp(typestr, "double") == 0) {
|
||||
r = double_format;
|
||||
}
|
||||
else if (strcmp(typestr, "float") == 0) {
|
||||
r = float_format;
|
||||
}
|
||||
else {
|
||||
if (strcmp(typestr, "double") != 0 && strcmp(typestr, "float") != 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"__getformat__() argument 1 must be "
|
||||
"'double' or 'float'");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case unknown_format:
|
||||
return PyUnicode_FromString("unknown");
|
||||
case ieee_little_endian_format:
|
||||
return PyUnicode_FromString("IEEE, little-endian");
|
||||
case ieee_big_endian_format:
|
||||
return PyUnicode_FromString("IEEE, big-endian");
|
||||
default:
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"insane float_format or double_format");
|
||||
return NULL;
|
||||
}
|
||||
return PyUnicode_FromString(_PY_FLOAT_LITTLE_ENDIAN ?
|
||||
"IEEE, little-endian" : "IEEE, big-endian");
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
float_getreal(PyObject *v, void *Py_UNUSED(closure))
|
||||
{
|
||||
@@ -1878,67 +1849,6 @@ PyTypeObject PyFloat_Type = {
|
||||
.tp_version_tag = _Py_TYPE_VERSION_FLOAT,
|
||||
};
|
||||
|
||||
static void
|
||||
_init_global_state(void)
|
||||
{
|
||||
float_format_type detected_double_format, detected_float_format;
|
||||
|
||||
/* We attempt to determine if this machine is using IEEE
|
||||
floating-point formats by peering at the bits of some
|
||||
carefully chosen values. If it looks like we are on an
|
||||
IEEE platform, the float packing/unpacking routines can
|
||||
just copy bits, if not they resort to arithmetic & shifts
|
||||
and masks. The shifts & masks approach works on all finite
|
||||
values, but what happens to infinities, NaNs and signed
|
||||
zeroes on packing is an accident, and attempting to unpack
|
||||
a NaN or an infinity will raise an exception.
|
||||
|
||||
Note that if we're on some whacked-out platform which uses
|
||||
IEEE formats but isn't strictly little-endian or big-
|
||||
endian, we will fall back to the portable shifts & masks
|
||||
method. */
|
||||
|
||||
#if SIZEOF_DOUBLE == 8
|
||||
{
|
||||
double x = 9006104071832581.0;
|
||||
if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0)
|
||||
detected_double_format = ieee_big_endian_format;
|
||||
else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0)
|
||||
detected_double_format = ieee_little_endian_format;
|
||||
else
|
||||
detected_double_format = unknown_format;
|
||||
}
|
||||
#else
|
||||
detected_double_format = unknown_format;
|
||||
#endif
|
||||
|
||||
#if SIZEOF_FLOAT == 4
|
||||
{
|
||||
float y = 16711938.0;
|
||||
if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0)
|
||||
detected_float_format = ieee_big_endian_format;
|
||||
else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0)
|
||||
detected_float_format = ieee_little_endian_format;
|
||||
else
|
||||
detected_float_format = unknown_format;
|
||||
}
|
||||
#else
|
||||
detected_float_format = unknown_format;
|
||||
#endif
|
||||
|
||||
double_format = detected_double_format;
|
||||
float_format = detected_float_format;
|
||||
}
|
||||
|
||||
void
|
||||
_PyFloat_InitState(PyInterpreterState *interp)
|
||||
{
|
||||
if (!_Py_IsMainInterpreter(interp)) {
|
||||
return;
|
||||
}
|
||||
_init_global_state();
|
||||
}
|
||||
|
||||
PyStatus
|
||||
_PyFloat_InitTypes(PyInterpreterState *interp)
|
||||
{
|
||||
@@ -2092,278 +2002,87 @@ int
|
||||
PyFloat_Pack4(double x, char *data, int le)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)data;
|
||||
if (float_format == unknown_format) {
|
||||
unsigned char sign;
|
||||
int e;
|
||||
double f;
|
||||
unsigned int fbits;
|
||||
int incr = 1;
|
||||
|
||||
if (le) {
|
||||
p += 3;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
sign = 1;
|
||||
x = -x;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
|
||||
f = frexp(x, &e);
|
||||
|
||||
/* Normalize f to be in the range [1.0, 2.0) */
|
||||
if (0.5 <= f && f < 1.0) {
|
||||
f *= 2.0;
|
||||
e--;
|
||||
}
|
||||
else if (f == 0.0)
|
||||
e = 0;
|
||||
else {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"frexp() result out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (e >= 128)
|
||||
goto Overflow;
|
||||
else if (e < -126) {
|
||||
/* Gradual underflow */
|
||||
f = ldexp(f, 126 + e);
|
||||
e = 0;
|
||||
}
|
||||
else if (!(e == 0 && f == 0.0)) {
|
||||
e += 127;
|
||||
f -= 1.0; /* Get rid of leading 1 */
|
||||
}
|
||||
|
||||
f *= 8388608.0; /* 2**23 */
|
||||
fbits = (unsigned int)(f + 0.5); /* Round */
|
||||
assert(fbits <= 8388608);
|
||||
if (fbits >> 23) {
|
||||
/* The carry propagated out of a string of 23 1 bits. */
|
||||
fbits = 0;
|
||||
++e;
|
||||
if (e >= 255)
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
/* First byte */
|
||||
*p = (sign << 7) | (e >> 1);
|
||||
p += incr;
|
||||
|
||||
/* Second byte */
|
||||
*p = (char) (((e & 1) << 7) | (fbits >> 16));
|
||||
p += incr;
|
||||
|
||||
/* Third byte */
|
||||
*p = (fbits >> 8) & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Fourth byte */
|
||||
*p = fbits & 0xFF;
|
||||
|
||||
/* Done */
|
||||
return 0;
|
||||
float y = (float)x;
|
||||
int i, incr = 1;
|
||||
|
||||
if (isinf(y) && !isinf(x)) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"float too large to pack with f format");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
float y = (float)x;
|
||||
int i, incr = 1;
|
||||
|
||||
if (isinf(y) && !isinf(x))
|
||||
goto Overflow;
|
||||
/* correct y if x was a sNaN, transformed to qNaN by conversion */
|
||||
if (isnan(x)) {
|
||||
uint64_t v;
|
||||
|
||||
/* correct y if x was a sNaN, transformed to qNaN by conversion */
|
||||
if (isnan(x)) {
|
||||
uint64_t v;
|
||||
|
||||
memcpy(&v, &x, 8);
|
||||
memcpy(&v, &x, 8);
|
||||
#ifndef __riscv
|
||||
if ((v & (1ULL << 51)) == 0) {
|
||||
uint32_t u32;
|
||||
memcpy(&u32, &y, 4);
|
||||
/* if have payload, make sNaN */
|
||||
if (u32 & 0x3fffff) {
|
||||
u32 &= ~(1 << 22);
|
||||
}
|
||||
memcpy(&y, &u32, 4);
|
||||
}
|
||||
#else
|
||||
if ((v & (1ULL << 51)) == 0) {
|
||||
uint32_t u32;
|
||||
|
||||
memcpy(&u32, &y, 4);
|
||||
/* Workaround RISC-V: "If a NaN value is converted to a
|
||||
* different floating-point type, the result is the
|
||||
* canonical NaN of the new type". The canonical NaN here
|
||||
* is a positive qNaN with zero payload. */
|
||||
if (v & (1ULL << 63)) {
|
||||
u32 |= (1 << 31); /* set sign */
|
||||
}
|
||||
/* add payload */
|
||||
u32 -= (u32 & 0x3fffff);
|
||||
u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
|
||||
/* if have payload, make sNaN */
|
||||
if ((v & (1ULL << 51)) == 0 && (u32 & 0x3fffff)) {
|
||||
if (u32 & 0x3fffff) {
|
||||
u32 &= ~(1 << 22);
|
||||
}
|
||||
|
||||
memcpy(&y, &u32, 4);
|
||||
}
|
||||
#else
|
||||
uint32_t u32;
|
||||
|
||||
memcpy(&u32, &y, 4);
|
||||
/* Workaround RISC-V: "If a NaN value is converted to a
|
||||
* different floating-point type, the result is the
|
||||
* canonical NaN of the new type". The canonical NaN here
|
||||
* is a positive qNaN with zero payload. */
|
||||
if (v & (1ULL << 63)) {
|
||||
u32 |= (1 << 31); /* set sign */
|
||||
}
|
||||
/* add payload */
|
||||
u32 -= (u32 & 0x3fffff);
|
||||
u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
|
||||
/* if have payload, make sNaN */
|
||||
if ((v & (1ULL << 51)) == 0 && (u32 & 0x3fffff)) {
|
||||
u32 &= ~(1 << 22);
|
||||
}
|
||||
|
||||
memcpy(&y, &u32, 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char s[sizeof(float)];
|
||||
memcpy(s, &y, sizeof(float));
|
||||
|
||||
if ((float_format == ieee_little_endian_format && !le)
|
||||
|| (float_format == ieee_big_endian_format && le)) {
|
||||
p += 3;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
*p = s[i];
|
||||
p += incr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"float too large to pack with f format");
|
||||
return -1;
|
||||
|
||||
unsigned char s[sizeof(float)];
|
||||
memcpy(s, &y, sizeof(float));
|
||||
|
||||
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
|
||||
p += 3;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
*p = s[i];
|
||||
p += incr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyFloat_Pack8(double x, char *data, int le)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)data;
|
||||
if (double_format == unknown_format) {
|
||||
unsigned char sign;
|
||||
int e;
|
||||
double f;
|
||||
unsigned int fhi, flo;
|
||||
int incr = 1;
|
||||
unsigned char as_bytes[8];
|
||||
memcpy(as_bytes, &x, 8);
|
||||
const unsigned char *s = as_bytes;
|
||||
int i, incr = 1;
|
||||
|
||||
if (le) {
|
||||
p += 7;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
sign = 1;
|
||||
x = -x;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
|
||||
f = frexp(x, &e);
|
||||
|
||||
/* Normalize f to be in the range [1.0, 2.0) */
|
||||
if (0.5 <= f && f < 1.0) {
|
||||
f *= 2.0;
|
||||
e--;
|
||||
}
|
||||
else if (f == 0.0)
|
||||
e = 0;
|
||||
else {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"frexp() result out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (e >= 1024)
|
||||
goto Overflow;
|
||||
else if (e < -1022) {
|
||||
/* Gradual underflow */
|
||||
f = ldexp(f, 1022 + e);
|
||||
e = 0;
|
||||
}
|
||||
else if (!(e == 0 && f == 0.0)) {
|
||||
e += 1023;
|
||||
f -= 1.0; /* Get rid of leading 1 */
|
||||
}
|
||||
|
||||
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
|
||||
f *= 268435456.0; /* 2**28 */
|
||||
fhi = (unsigned int)f; /* Truncate */
|
||||
assert(fhi < 268435456);
|
||||
|
||||
f -= (double)fhi;
|
||||
f *= 16777216.0; /* 2**24 */
|
||||
flo = (unsigned int)(f + 0.5); /* Round */
|
||||
assert(flo <= 16777216);
|
||||
if (flo >> 24) {
|
||||
/* The carry propagated out of a string of 24 1 bits. */
|
||||
flo = 0;
|
||||
++fhi;
|
||||
if (fhi >> 28) {
|
||||
/* And it also propagated out of the next 28 bits. */
|
||||
fhi = 0;
|
||||
++e;
|
||||
if (e >= 2047)
|
||||
goto Overflow;
|
||||
}
|
||||
}
|
||||
|
||||
/* First byte */
|
||||
*p = (sign << 7) | (e >> 4);
|
||||
p += incr;
|
||||
|
||||
/* Second byte */
|
||||
*p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24));
|
||||
p += incr;
|
||||
|
||||
/* Third byte */
|
||||
*p = (fhi >> 16) & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Fourth byte */
|
||||
*p = (fhi >> 8) & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Fifth byte */
|
||||
*p = fhi & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Sixth byte */
|
||||
*p = (flo >> 16) & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Seventh byte */
|
||||
*p = (flo >> 8) & 0xFF;
|
||||
p += incr;
|
||||
|
||||
/* Eighth byte */
|
||||
*p = flo & 0xFF;
|
||||
/* p += incr; */
|
||||
|
||||
/* Done */
|
||||
return 0;
|
||||
|
||||
Overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"float too large to pack with d format");
|
||||
return -1;
|
||||
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
|
||||
p += 7;
|
||||
incr = -1;
|
||||
}
|
||||
else {
|
||||
unsigned char as_bytes[8];
|
||||
memcpy(as_bytes, &x, 8);
|
||||
const unsigned char *s = as_bytes;
|
||||
int i, incr = 1;
|
||||
|
||||
if ((double_format == ieee_little_endian_format && !le)
|
||||
|| (double_format == ieee_big_endian_format && le)) {
|
||||
p += 7;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
*p = *s++;
|
||||
p += incr;
|
||||
}
|
||||
return 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
*p = *s++;
|
||||
p += incr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double
|
||||
@@ -2426,208 +2145,79 @@ double
|
||||
PyFloat_Unpack4(const char *data, int le)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)data;
|
||||
if (float_format == unknown_format) {
|
||||
unsigned char sign;
|
||||
int e;
|
||||
unsigned int f;
|
||||
double x;
|
||||
int incr = 1;
|
||||
float x;
|
||||
|
||||
if (le) {
|
||||
p += 3;
|
||||
incr = -1;
|
||||
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
|
||||
char buf[4];
|
||||
char *d = &buf[3];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
*d-- = *p++;
|
||||
}
|
||||
|
||||
/* First byte */
|
||||
sign = (*p >> 7) & 1;
|
||||
e = (*p & 0x7F) << 1;
|
||||
p += incr;
|
||||
|
||||
/* Second byte */
|
||||
e |= (*p >> 7) & 1;
|
||||
f = (*p & 0x7F) << 16;
|
||||
p += incr;
|
||||
|
||||
if (e == 255) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"can't unpack IEEE 754 special value "
|
||||
"on non-IEEE platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Third byte */
|
||||
f |= *p << 8;
|
||||
p += incr;
|
||||
|
||||
/* Fourth byte */
|
||||
f |= *p;
|
||||
|
||||
x = (double)f / 8388608.0;
|
||||
|
||||
/* XXX This sadly ignores Inf/NaN issues */
|
||||
if (e == 0)
|
||||
e = -126;
|
||||
else {
|
||||
x += 1.0;
|
||||
e -= 127;
|
||||
}
|
||||
x = ldexp(x, e);
|
||||
|
||||
if (sign)
|
||||
x = -x;
|
||||
|
||||
return x;
|
||||
memcpy(&x, buf, 4);
|
||||
}
|
||||
else {
|
||||
float x;
|
||||
memcpy(&x, p, 4);
|
||||
}
|
||||
|
||||
if ((float_format == ieee_little_endian_format && !le)
|
||||
|| (float_format == ieee_big_endian_format && le)) {
|
||||
char buf[4];
|
||||
char *d = &buf[3];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
*d-- = *p++;
|
||||
}
|
||||
memcpy(&x, buf, 4);
|
||||
}
|
||||
else {
|
||||
memcpy(&x, p, 4);
|
||||
}
|
||||
|
||||
/* return sNaN double if x was sNaN float */
|
||||
if (isnan(x)) {
|
||||
uint32_t v;
|
||||
memcpy(&v, &x, 4);
|
||||
/* return sNaN double if x was sNaN float */
|
||||
if (isnan(x)) {
|
||||
uint32_t v;
|
||||
memcpy(&v, &x, 4);
|
||||
|
||||
#ifndef __riscv
|
||||
if ((v & (1 << 22)) == 0) {
|
||||
double y = x; /* will make qNaN double */
|
||||
uint64_t u64;
|
||||
memcpy(&u64, &y, 8);
|
||||
u64 &= ~(1ULL << 51); /* make sNaN */
|
||||
memcpy(&y, &u64, 8);
|
||||
return y;
|
||||
}
|
||||
#else
|
||||
double y = x;
|
||||
if ((v & (1 << 22)) == 0) {
|
||||
double y = x; /* will make qNaN double */
|
||||
uint64_t u64;
|
||||
|
||||
memcpy(&u64, &y, 8);
|
||||
if ((v & (1 << 22)) == 0) {
|
||||
u64 &= ~(1ULL << 51);
|
||||
}
|
||||
/* Workaround RISC-V, see PyFloat_Pack4() */
|
||||
if (v & (1 << 31)) {
|
||||
u64 |= (1ULL << 63); /* set sign */
|
||||
}
|
||||
/* add payload */
|
||||
u64 -= (u64 & 0x7ffffffffffffULL);
|
||||
u64 += ((v & 0x3fffffULL) << 29);
|
||||
|
||||
u64 &= ~(1ULL << 51); /* make sNaN */
|
||||
memcpy(&y, &u64, 8);
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
double y = x;
|
||||
uint64_t u64;
|
||||
|
||||
return x;
|
||||
memcpy(&u64, &y, 8);
|
||||
if ((v & (1 << 22)) == 0) {
|
||||
u64 &= ~(1ULL << 51);
|
||||
}
|
||||
/* Workaround RISC-V, see PyFloat_Pack4() */
|
||||
if (v & (1 << 31)) {
|
||||
u64 |= (1ULL << 63); /* set sign */
|
||||
}
|
||||
/* add payload */
|
||||
u64 -= (u64 & 0x7ffffffffffffULL);
|
||||
u64 += ((v & 0x3fffffULL) << 29);
|
||||
|
||||
memcpy(&y, &u64, 8);
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
double
|
||||
PyFloat_Unpack8(const char *data, int le)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)data;
|
||||
if (double_format == unknown_format) {
|
||||
unsigned char sign;
|
||||
int e;
|
||||
unsigned int fhi, flo;
|
||||
double x;
|
||||
int incr = 1;
|
||||
double x;
|
||||
|
||||
if (le) {
|
||||
p += 7;
|
||||
incr = -1;
|
||||
if ((_PY_FLOAT_LITTLE_ENDIAN && !le) || (_PY_FLOAT_BIG_ENDIAN && le)) {
|
||||
char buf[8];
|
||||
char *d = &buf[7];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
*d-- = *p++;
|
||||
}
|
||||
|
||||
/* First byte */
|
||||
sign = (*p >> 7) & 1;
|
||||
e = (*p & 0x7F) << 4;
|
||||
|
||||
p += incr;
|
||||
|
||||
/* Second byte */
|
||||
e |= (*p >> 4) & 0xF;
|
||||
fhi = (*p & 0xF) << 24;
|
||||
p += incr;
|
||||
|
||||
if (e == 2047) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"can't unpack IEEE 754 special value "
|
||||
"on non-IEEE platform");
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
/* Third byte */
|
||||
fhi |= *p << 16;
|
||||
p += incr;
|
||||
|
||||
/* Fourth byte */
|
||||
fhi |= *p << 8;
|
||||
p += incr;
|
||||
|
||||
/* Fifth byte */
|
||||
fhi |= *p;
|
||||
p += incr;
|
||||
|
||||
/* Sixth byte */
|
||||
flo = *p << 16;
|
||||
p += incr;
|
||||
|
||||
/* Seventh byte */
|
||||
flo |= *p << 8;
|
||||
p += incr;
|
||||
|
||||
/* Eighth byte */
|
||||
flo |= *p;
|
||||
|
||||
x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
|
||||
x /= 268435456.0; /* 2**28 */
|
||||
|
||||
if (e == 0)
|
||||
e = -1022;
|
||||
else {
|
||||
x += 1.0;
|
||||
e -= 1023;
|
||||
}
|
||||
x = ldexp(x, e);
|
||||
|
||||
if (sign)
|
||||
x = -x;
|
||||
|
||||
return x;
|
||||
memcpy(&x, buf, 8);
|
||||
}
|
||||
else {
|
||||
double x;
|
||||
|
||||
if ((double_format == ieee_little_endian_format && !le)
|
||||
|| (double_format == ieee_big_endian_format && le)) {
|
||||
char buf[8];
|
||||
char *d = &buf[7];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
*d-- = *p++;
|
||||
}
|
||||
memcpy(&x, buf, 8);
|
||||
}
|
||||
else {
|
||||
memcpy(&x, p, 8);
|
||||
}
|
||||
|
||||
return x;
|
||||
memcpy(&x, p, 8);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
+2
-4
@@ -139,8 +139,7 @@
|
||||
#ifdef DOUBLE_IS_LITTLE_ENDIAN_IEEE754
|
||||
# define IEEE_8087
|
||||
#endif
|
||||
#if defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) || \
|
||||
defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
|
||||
#if defined(DOUBLE_IS_BIG_ENDIAN_IEEE754)
|
||||
# define IEEE_MC68k
|
||||
#endif
|
||||
#if defined(IEEE_8087) + defined(IEEE_MC68k) != 1
|
||||
@@ -149,8 +148,7 @@
|
||||
|
||||
/* The code below assumes that the endianness of integers matches the
|
||||
endianness of the two 32-bit words of a double. Check this. */
|
||||
#if defined(WORDS_BIGENDIAN) && (defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) || \
|
||||
defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754))
|
||||
#if defined(WORDS_BIGENDIAN) && defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754)
|
||||
#error "doubles and ints have incompatible endianness"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -706,8 +706,6 @@ pycore_init_global_objects(PyInterpreterState *interp)
|
||||
{
|
||||
PyStatus status;
|
||||
|
||||
_PyFloat_InitState(interp);
|
||||
|
||||
status = _PyUnicode_InitGlobalObjects(interp);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
|
||||
@@ -26212,20 +26212,7 @@ printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h
|
||||
printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h
|
||||
;;
|
||||
*)
|
||||
case $host_cpu in #(
|
||||
*arm*) :
|
||||
# Some ARM platforms use a mixed-endian representation for
|
||||
# doubles. While Python doesn't currently have full support
|
||||
# for these platforms (see e.g., issue 1762561), we can at
|
||||
# least make sure that float <-> string conversions work.
|
||||
# FLOAT_WORDS_BIGENDIAN doesn't actually detect this case,
|
||||
# but if it's not big or little, then it must be this?
|
||||
|
||||
printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h
|
||||
;; #(
|
||||
*) :
|
||||
as_fn_error $? "Unknown float word ordering. You need to manually preset ax_cv_c_float_words_bigendian=no (or yes) according to your system." "$LINENO" 5 ;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
+2
-12
@@ -6178,21 +6178,11 @@ AX_C_FLOAT_WORDS_BIGENDIAN(
|
||||
[AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1],
|
||||
[Define if C doubles are 64-bit IEEE 754 binary format,
|
||||
stored with the least significant byte first])],
|
||||
[AS_CASE([$host_cpu],
|
||||
[*arm*], [# Some ARM platforms use a mixed-endian representation for
|
||||
# doubles. While Python doesn't currently have full support
|
||||
# for these platforms (see e.g., issue 1762561), we can at
|
||||
# least make sure that float <-> string conversions work.
|
||||
# FLOAT_WORDS_BIGENDIAN doesn't actually detect this case,
|
||||
# but if it's not big or little, then it must be this?
|
||||
AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1],
|
||||
[Define if C doubles are 64-bit IEEE 754 binary format,
|
||||
stored in ARM mixed-endian order (byte order 45670123)])],
|
||||
[AC_MSG_ERROR([m4_normalize([
|
||||
[AC_MSG_ERROR([m4_normalize([
|
||||
Unknown float word ordering. You need to manually
|
||||
preset ax_cv_c_float_words_bigendian=no (or yes)
|
||||
according to your system.
|
||||
])])])])
|
||||
])])])
|
||||
|
||||
# The short float repr introduced in Python 3.1 requires the
|
||||
# correctly-rounded string <-> double conversion functions from
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
/* The Android API level. */
|
||||
#undef ANDROID_API_LEVEL
|
||||
|
||||
/* Define if C doubles are 64-bit IEEE 754 binary format, stored in ARM
|
||||
mixed-endian order (byte order 45670123) */
|
||||
#undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754
|
||||
|
||||
/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the most
|
||||
significant byte first */
|
||||
#undef DOUBLE_IS_BIG_ENDIAN_IEEE754
|
||||
|
||||
Reference in New Issue
Block a user