]> granicus.if.org Git - python/commitdiff
Fix compile.c so that it records 0.0 and -0.0 as separate constants in a code
authorAlex Martelli <aleaxit@gmail.com>
Wed, 22 Aug 2007 21:14:17 +0000 (21:14 +0000)
committerAlex Martelli <aleaxit@gmail.com>
Wed, 22 Aug 2007 21:14:17 +0000 (21:14 +0000)
object's co_consts tuple; add a test to show that the previous behavior (where
these two constants were "collapsed" into one) causes serious malfunctioning.

Lib/test/test_float.py
Python/compile.c

index fb47db8eb087adb749e3176b89cda197cf437325..1c74c96d3c22f14cea2eced6b4cf99ba5e45decc 100644 (file)
@@ -81,6 +81,7 @@ class UnknownFormatTestCase(unittest.TestCase):
 # on an IEEE platform, all we guarantee is that bit patterns
 # representing infinities or NaNs do not raise an exception; all else
 # is accident (today).
+# let's also try to guarantee that -0.0 and 0.0 don't get confused.
 
 class IEEEFormatTestCase(unittest.TestCase):
     if float.__getformat__("double").startswith("IEEE"):
@@ -99,6 +100,20 @@ class IEEEFormatTestCase(unittest.TestCase):
                               ('<f', LE_FLOAT_NAN)]:
                 struct.unpack(fmt, data)
 
+    if float.__getformat__("double").startswith("IEEE"):
+        def test_negative_zero(self):
+            import math
+            def pos_pos():
+                return 0.0, math.atan2(0.0, -1)
+            def pos_neg():
+                return 0.0, math.atan2(-0.0, -1)
+            def neg_pos():
+                return -0.0, math.atan2(0.0, -1)
+            def neg_neg():
+                return -0.0, math.atan2(-0.0, -1)
+            self.assertEquals(pos_pos(), neg_pos())
+            self.assertEquals(pos_neg(), neg_neg())
+
 
 def test_main():
     test_support.run_unittest(
index 01dbb1aaa3ac84dc9bee4924bd88e4a41f393124..eed13792d288fa5e0173f08790ca12c8623af112 100644 (file)
@@ -907,7 +907,20 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
        Py_ssize_t arg;
 
        /* necessary to make sure types aren't coerced (e.g., int and long) */
-       t = PyTuple_Pack(2, o, o->ob_type);
+        /* _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);
+        }
        if (t == NULL)
            return -1;