Index: Objects/complexobject.c =================================================================== --- Objects/complexobject.c (revision 86635) +++ Objects/complexobject.c (working copy) @@ -799,28 +799,23 @@ s++; } - /* a valid complex string usually takes one of the three forms: + /* A valid complex string usually takes one of the three forms: - real part only j - imaginary part only - j - real and imaginary parts + j - real and imaginary parts - where represents any numeric string that's accepted by the - float constructor (including 'nan', 'inf', 'infinity', etc.), and - is any string of the form whose first - character is '+' or '-'. + where represents any numeric string that's accepted by the float + constructor (including 'nan', 'inf', 'infinity', etc., and the optional + leading '+' or '-'), and takes the form + , with either '+' or '-'. - For backwards compatibility, the extra forms - - j - j - j - - are also accepted, though support for these forms may be removed from - a future version of Python. + For backwards compatibility, '+j', 'j' and '-j' are also permitted in + place of 'j' in the second and third forms above, although + support for this may be removed from a future version of Python. */ - /* first look for forms starting with */ + /* All the usual forms start with . */ z = PyOS_string_to_double(s, &end, NULL); if (z == -1.0 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_ValueError)) @@ -829,52 +824,79 @@ goto error; } if (end != s) { - /* all 4 forms starting with land here */ s = end; - if (*s == '+' || *s == '-') { - /* j | j */ - x = z; - y = PyOS_string_to_double(s, &end, NULL); - if (y == -1.0 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_ValueError)) - PyErr_Clear(); - else - goto error; - } - if (end != s) - /* j */ - s = end; - else { - /* j */ - y = *s == '+' ? 1.0 : -1.0; - s++; - } - if (!(*s == 'j' || *s == 'J')) - goto parse_error; - s++; - } - else if (*s == 'j' || *s == 'J') { + /* Successfully parsed . Was it the beginning of an imaginary + literal? */ + if (*s == 'j' || *s == 'J') { /* j */ s++; y = z; } - else - /* */ + else { + int got_binop, negate_imag; + /* No 'j', so z must be the real part. */ x = z; + /* Look for . */ + negate_imag = got_binop = 0; + while (Py_ISSPACE(*s)) + s++; + if (*s == '+' || *s == '-') { + got_binop = 1; + if (*s == '-') + negate_imag = 1; + s++; + while (Py_ISSPACE(*s)) + s++; + } + if (got_binop) { + /* j */ + z = PyOS_string_to_double(s, &end, NULL); + if (z == -1.0 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_ValueError)) + PyErr_Clear(); + else + goto error; + } + if (end != s) { + /* Successfully parsed . */ + s = end; + } + else { + /* Look for one of the special forms +j, -j, j. */ + z = 1.0; + if (*s == '+' || *s == '-') { + if (*s == '-') { + z = -1.0; + } + s++; + } + } + if (*s == 'j' || *s == 'J') { + s++; + y = negate_imag ? -z : z; + } + else { + goto parse_error; + } + } + } } else { - /* not starting with ; must be j or j */ + /* Special form +j, -j, j. */ + z = 1.0; if (*s == '+' || *s == '-') { - /* j */ - y = *s == '+' ? 1.0 : -1.0; + if (*s == '-') { + z = -1.0; + } s++; } - else - /* j */ - y = 1.0; - if (!(*s == 'j' || *s == 'J')) + if (*s == 'j' || *s == 'J') { + s++; + y = z; + } + else { goto parse_error; - s++; + } } /* trailing whitespace and closing bracket */ Index: Lib/test/test_complex.py =================================================================== --- Lib/test/test_complex.py (revision 86635) +++ Lib/test/test_complex.py (working copy) @@ -61,6 +61,16 @@ msg += ': zeros have different signs' self.fail(msg.format(x, y)) + def assertComplexIdentical(self, x, y): + """Fail unless complex numbers x and y have equal values and signs. + + In particular, if x and y both have real (or imaginary) part + zero, but the zeros have different signs, this test will fail. + + """ + self.assertFloatsAreIdentical(x.real, y.real) + self.assertFloatsAreIdentical(x.imag, y.imag) + def assertClose(self, x, y, eps=1e-9): """Return true iff complexes x and y "are close\"""" self.assertCloseAbs(x.real, y.real, eps) @@ -266,6 +276,26 @@ self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j) self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j) + self.assertComplexIdentical(complex('1++1j'), complex(1.0, 1.0)) + self.assertComplexIdentical(complex('1+-1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('1-+1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('1--1j'), complex(1.0, 1.0)) + self.assertComplexIdentical(complex('1j'), complex(0.0, 1.0)) + self.assertComplexIdentical(complex('1+1j'), complex(1.0, 1.0)) + self.assertComplexIdentical(complex('1-1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('+1j'), complex(0.0, 1.0)) + self.assertComplexIdentical(complex('-1j'), complex(0.0, -1.0)) + self.assertComplexIdentical(complex('+1j'), complex(0.0, 1.0)) + self.assertComplexIdentical(complex('-1j'), complex(0.0, -1.0)) + + # Spacing permitted around central binary operator + self.assertComplexIdentical(complex('1 + 1j'), complex(1.0, 1.0)) + self.assertComplexIdentical(complex('1 - 1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('1 + +1j'), complex(1.0, 1.0)) + self.assertComplexIdentical(complex('1 - +1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('1 + -1j'), complex(1.0, -1.0)) + self.assertComplexIdentical(complex('1 - -1j'), complex(1.0, +1.0)) + class complex2(complex): pass self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j) self.assertAlmostEqual(complex(real=17, imag=23), 17+23j)