From 105be7725b88ecef826ac07392a4236bae934bf6 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Thu, 31 Jan 2008 22:17:37 +0000 Subject: [PATCH] Issue #1678380. Fix a bug that identifies 0j and -0j when they appear in the same code unit. The fix is essentially the same as the fix for a previous bug identifying 0. and -0. --- Lib/test/test_complex.py | 7 +++++ Misc/NEWS | 3 ++ Python/compile.c | 59 ++++++++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 64297e2264f..bd3890e3398 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -359,6 +359,13 @@ class ComplexTest(unittest.TestCase): except (OSError, IOError): pass + if float.__getformat__("double").startswith("IEEE"): + def test_plus_minus_0j(self): + # test that -0j and 0j literals are not identified + z1, z2 = 0j, -0j + self.assertEquals(atan2(z1.imag, -1.), atan2(0., -1.)) + self.assertEquals(atan2(z2.imag, -1.), atan2(-0., -1.)) + def test_main(): test_support.run_unittest(ComplexTest) diff --git a/Misc/NEWS b/Misc/NEWS index 7b36919c9e8..45b266cffc4 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1? Core and builtins ----------------- +- Issue #1678380: Fix a bug that identifies 0j and -0j when they appear + in the same code unit. + - Patch #1970 by Antoine Pitrou: Speedup unicode whitespace and linebreak detection diff --git a/Python/compile.c b/Python/compile.c index 3501b954ecc..0dd1082151e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -907,24 +907,59 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) { PyObject *t, *v; Py_ssize_t arg; + unsigned char *p, *q; + Py_complex z; + double d; + int real_part_zero, imag_part_zero; /* 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)) { - double d = PyFloat_AS_DOUBLE(o); - unsigned char* 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) - t = PyTuple_Pack(3, o, o->ob_type, Py_None); - else - t = PyTuple_Pack(2, o, o->ob_type); - } else { - t = PyTuple_Pack(2, o, o->ob_type); + 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) + t = PyTuple_Pack(3, o, o->ob_type, Py_None); + else + t = PyTuple_Pack(2, o, o->ob_type); + } + else if (PyComplex_Check(o)) { + /* 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.*/ + 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); + } + else if (real_part_zero && !imag_part_zero) { + t = PyTuple_Pack(4, o, o->ob_type, Py_True, Py_False); + } + else if (!real_part_zero && imag_part_zero) { + t = PyTuple_Pack(4, o, o->ob_type, Py_False, Py_True); + } + else { + t = PyTuple_Pack(2, o, o->ob_type); + } + } + else { + t = PyTuple_Pack(2, o, o->ob_type); } if (t == NULL) - return -1; + return -1; v = PyDict_GetItem(dict, t); if (!v) {