From ccc690d650f0b784c5d0445d0c34d372d2d24ec3 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 28 Nov 2009 16:32:27 +0000 Subject: [PATCH] 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. --- Python/compile.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 35ee48be11a..03875a5b38a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -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);