mirror of https://github.com/python/cpython
Issue #1678380: When distinguishing between -0.0 and 0.0 in
compiler_add_o, use copysign instead of examining the first and last bytes of the double. The latter method fails for little-endian ARM, OABI, where doubles are little-endian but with the words swapped.
This commit is contained in:
parent
d16f57bf4d
commit
ccc690d650
|
@ -910,18 +910,16 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
|
|||
{
|
||||
PyObject *t, *v;
|
||||
Py_ssize_t arg;
|
||||
unsigned char *p;
|
||||
double d;
|
||||
|
||||
/* necessary to make sure types aren't coerced (e.g., int and long) */
|
||||
/* _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms */
|
||||
if (PyFloat_Check(o)) {
|
||||
d = PyFloat_AS_DOUBLE(o);
|
||||
p = (unsigned char*) &d;
|
||||
/* all we need is to make the tuple different in either the 0.0
|
||||
* or -0.0 case from all others, just to avoid the "coercion".
|
||||
*/
|
||||
if (*p==0 && p[sizeof(double)-1]==0)
|
||||
if (d == 0.0 && copysign(1.0, d) < 0.0)
|
||||
t = PyTuple_Pack(3, o, o->ob_type, Py_None);
|
||||
else
|
||||
t = PyTuple_Pack(2, o, o->ob_type);
|
||||
|
@ -929,32 +927,23 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
|
|||
#ifndef WITHOUT_COMPLEX
|
||||
else if (PyComplex_Check(o)) {
|
||||
Py_complex z;
|
||||
int real_part_zero, imag_part_zero;
|
||||
unsigned char *q;
|
||||
/* complex case is even messier: we need to make complex(x,
|
||||
0.) different from complex(x, -0.) and complex(0., y)
|
||||
different from complex(-0., y), for any x and y. In
|
||||
particular, all four complex zeros should be
|
||||
distinguished.*/
|
||||
int real_negzero, imag_negzero;
|
||||
/* For the complex case we must make complex(x, 0.)
|
||||
different from complex(x, -0.) and complex(0., y)
|
||||
different from complex(-0., y), for any x and y.
|
||||
All four complex zeros must be distinguished.*/
|
||||
z = PyComplex_AsCComplex(o);
|
||||
p = (unsigned char*) &(z.real);
|
||||
q = (unsigned char*) &(z.imag);
|
||||
/* all that matters here is that on IEEE platforms
|
||||
real_part_zero will be true if z.real == 0., and false if
|
||||
z.real == -0. In fact, real_part_zero will also be true
|
||||
for some other rarely occurring nonzero floats, but this
|
||||
doesn't matter. Similar comments apply to
|
||||
imag_part_zero. */
|
||||
real_part_zero = *p==0 && p[sizeof(double)-1]==0;
|
||||
imag_part_zero = *q==0 && q[sizeof(double)-1]==0;
|
||||
if (real_part_zero && imag_part_zero) {
|
||||
t = PyTuple_Pack(4, o, o->ob_type, Py_True, Py_True);
|
||||
real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0;
|
||||
imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0;
|
||||
if (real_negzero && imag_negzero) {
|
||||
t = PyTuple_Pack(5, o, o->ob_type,
|
||||
Py_None, Py_None, Py_None);
|
||||
}
|
||||
else if (real_part_zero && !imag_part_zero) {
|
||||
t = PyTuple_Pack(4, o, o->ob_type, Py_True, Py_False);
|
||||
else if (imag_negzero) {
|
||||
t = PyTuple_Pack(4, o, o->ob_type, Py_None, Py_None);
|
||||
}
|
||||
else if (!real_part_zero && imag_part_zero) {
|
||||
t = PyTuple_Pack(4, o, o->ob_type, Py_False, Py_True);
|
||||
else if (real_negzero) {
|
||||
t = PyTuple_Pack(3, o, o->ob_type, Py_None);
|
||||
}
|
||||
else {
|
||||
t = PyTuple_Pack(2, o, o->ob_type);
|
||||
|
|
Loading…
Reference in New Issue