summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2008-01-31 22:17:37 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2008-01-31 22:17:37 (GMT)
commit105be7725b88ecef826ac07392a4236bae934bf6 (patch)
tree7975fc1a3f2b5f982c4ee87ddd360f53922c2d2e
parent2df20a3e0816537db68618cef0603e89773beac4 (diff)
downloadcpython-105be7725b88ecef826ac07392a4236bae934bf6.zip
cpython-105be7725b88ecef826ac07392a4236bae934bf6.tar.gz
cpython-105be7725b88ecef826ac07392a4236bae934bf6.tar.bz2
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.
-rw-r--r--Lib/test/test_complex.py7
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/compile.c59
3 files changed, 57 insertions, 12 deletions
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py
index 64297e2..bd3890e 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 7b36919..45b266c 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 3501b95..0dd1082 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) {