]> granicus.if.org Git - python/commitdiff
Issue #1678380. Fix a bug that identifies 0j and -0j when they appear
authorMark Dickinson <dickinsm@gmail.com>
Thu, 31 Jan 2008 22:17:37 +0000 (22:17 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Thu, 31 Jan 2008 22:17:37 +0000 (22:17 +0000)
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
Misc/NEWS
Python/compile.c

index 64297e2264f0f2b5e13c63ded614f6ed19fd7e79..bd3890e3398cde979853b966380e5427d82f4447 100644 (file)
@@ -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)
 
index 7b36919c9e82f0095a974f1bd5e07280b91c1571..45b266cffc481804b82762fab94ea5a58065fa29 100644 (file)
--- 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
 
index 3501b954ecc035733c2c7312f71e8be35b2844f8..0dd1082151e7c6ffc37f22afd19341df19684050 100644 (file)
@@ -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) {