bpo-40269: Fix repr for complex.
eval(repr(z)) restores now the sign of zero components of z.
This commit is contained in:
parent
482259d0dc
commit
18eac99151
|
@ -473,7 +473,7 @@ class ComplexTest(unittest.TestCase):
|
|||
test(complex(NAN, NAN), "(nan+nanj)")
|
||||
|
||||
test(complex(0, INF), "infj")
|
||||
test(complex(0, -INF), "-infj")
|
||||
test(complex(0, -INF), "(0-infj)")
|
||||
test(complex(0, NAN), "nanj")
|
||||
|
||||
self.assertEqual(1-6j,complex(repr(1-6j)))
|
||||
|
@ -487,15 +487,24 @@ class ComplexTest(unittest.TestCase):
|
|||
test_fn(repr(v), expected)
|
||||
test_fn(str(v), expected)
|
||||
|
||||
for x in 0.0, -0.0, 1.0, -1.0:
|
||||
for y in 0.0, -0.0, 1.0, -1.0:
|
||||
r = repr(complex(x, y))
|
||||
with self.subTest(real=x, imag=y, repr=r):
|
||||
z = eval(r)
|
||||
self.assertEqual(z, complex(x, y))
|
||||
self.assertFloatsAreIdentical(z.real, x)
|
||||
self.assertFloatsAreIdentical(z.imag, y)
|
||||
|
||||
test(complex(0., 1.), "1j")
|
||||
test(complex(-0., 1.), "(-0+1j)")
|
||||
test(complex(0., -1.), "-1j")
|
||||
test(complex(-0., -1.), "(-0-1j)")
|
||||
test(complex(-0., 1.), "-(0-1j)")
|
||||
test(complex(0., -1.), "(0-1j)")
|
||||
test(complex(-0., -1.), "(-0.0-1j)")
|
||||
|
||||
test(complex(0., 0.), "0j")
|
||||
test(complex(0., -0.), "-0j")
|
||||
test(complex(-0., 0.), "(-0+0j)")
|
||||
test(complex(-0., -0.), "(-0-0j)")
|
||||
test(complex(0., -0.), "-(-0.0-0j)")
|
||||
test(complex(-0., 0.), "(-0.0-0j)")
|
||||
test(complex(-0., -0.), "-(0+0j)")
|
||||
|
||||
def test_neg(self):
|
||||
self.assertEqual(-(1+6j), -1-6j)
|
||||
|
@ -563,9 +572,11 @@ class ComplexTest(unittest.TestCase):
|
|||
for x in vals:
|
||||
for y in vals:
|
||||
z = complex(x, y)
|
||||
roundtrip = complex(repr(z))
|
||||
self.assertFloatsAreIdentical(z.real, roundtrip.real)
|
||||
self.assertFloatsAreIdentical(z.imag, roundtrip.imag)
|
||||
r = repr(z)
|
||||
with self.subTest(x=x, y=y, repr=r):
|
||||
roundtrip = complex(r)
|
||||
self.assertFloatsAreIdentical(z.real, roundtrip.real)
|
||||
self.assertFloatsAreIdentical(z.imag, roundtrip.imag)
|
||||
|
||||
# if we predefine some constants, then eval(repr(z)) should
|
||||
# also work, except that it might change the sign of zeros
|
||||
|
|
|
@ -353,8 +353,6 @@ PyComplex_AsCComplex(PyObject *op)
|
|||
static PyObject *
|
||||
complex_repr(PyComplexObject *v)
|
||||
{
|
||||
int precision = 0;
|
||||
char format_code = 'r';
|
||||
PyObject *result = NULL;
|
||||
|
||||
/* If these are non-NULL, they'll need to be freed. */
|
||||
|
@ -366,37 +364,80 @@ complex_repr(PyComplexObject *v)
|
|||
are pointers to constants. */
|
||||
const char *re = NULL;
|
||||
const char *lead = "";
|
||||
const char *tail = "";
|
||||
const char *tail = ")";
|
||||
|
||||
if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) {
|
||||
/* Real part is +0: just output the imaginary part and do not
|
||||
include parens. */
|
||||
if (v->cval.real == 0.0
|
||||
&& copysign(1.0, v->cval.real) > 0.0
|
||||
&& copysign(1.0, v->cval.imag) > 0.0)
|
||||
{
|
||||
/* Real part is +0, imaginary part is not negative: just output
|
||||
the imaginary part and do not include parens. */
|
||||
re = "";
|
||||
im = PyOS_double_to_string(v->cval.imag, format_code,
|
||||
precision, 0, NULL);
|
||||
if (!im) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
im = PyOS_double_to_string(v->cval.imag, 'r', 0, 0, NULL);
|
||||
tail = "";
|
||||
}
|
||||
else
|
||||
if (v->cval.real == 0.0
|
||||
&& v->cval.imag == 0.0
|
||||
&& copysign(1.0, v->cval.real) != copysign(1.0, v->cval.imag))
|
||||
{
|
||||
/* Real part is +0, imaginary part is -0 or
|
||||
real part is -0, imaginary part is +0. */
|
||||
re = "-0.0";
|
||||
im = PyOS_double_to_string(-0.0, 'r', 0, Py_DTSF_SIGN, NULL);
|
||||
lead = copysign(1.0, v->cval.real) > 0.0 ? "-(" : "(";
|
||||
}
|
||||
else
|
||||
if (v->cval.real == 0.0
|
||||
&& copysign(1.0, v->cval.real) < 0.0
|
||||
&& copysign(1.0, v->cval.imag) > 0.0)
|
||||
{
|
||||
/* Real part is -0, imaginary part is not negative. */
|
||||
re = "0";
|
||||
im = PyOS_double_to_string(-v->cval.imag, 'r', 0, Py_DTSF_SIGN, NULL);
|
||||
lead = "-(";
|
||||
}
|
||||
else
|
||||
if (v->cval.imag == 0.0
|
||||
&& copysign(1.0, v->cval.imag) < 0.0)
|
||||
{
|
||||
/* Imaginary part is -0. */
|
||||
if (v->cval.real == 0.0 && copysign(1.0, v->cval.real) > 0.0) {
|
||||
re = "-0.0";
|
||||
}
|
||||
} else {
|
||||
else {
|
||||
pre = PyOS_double_to_string(-v->cval.real, 'r', 0, 0, NULL);
|
||||
if (!pre) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
re = pre;
|
||||
}
|
||||
|
||||
im = PyOS_double_to_string(-v->cval.imag, 'r', 0, Py_DTSF_SIGN, NULL);
|
||||
lead = "-(";
|
||||
}
|
||||
else {
|
||||
/* Format imaginary part with sign, real part without. Include
|
||||
parens in the result. */
|
||||
pre = PyOS_double_to_string(v->cval.real, format_code,
|
||||
precision, 0, NULL);
|
||||
if (!pre) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
if (v->cval.real == 0.0 && copysign(1.0, v->cval.real) < 0.0) {
|
||||
re = "-0.0";
|
||||
}
|
||||
else {
|
||||
pre = PyOS_double_to_string(v->cval.real, 'r', 0, 0, NULL);
|
||||
if (!pre) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
re = pre;
|
||||
}
|
||||
re = pre;
|
||||
|
||||
im = PyOS_double_to_string(v->cval.imag, format_code,
|
||||
precision, Py_DTSF_SIGN, NULL);
|
||||
if (!im) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
im = PyOS_double_to_string(v->cval.imag, 'r', 0, Py_DTSF_SIGN, NULL);
|
||||
lead = "(";
|
||||
tail = ")";
|
||||
}
|
||||
if (!im) {
|
||||
PyErr_NoMemory();
|
||||
goto done;
|
||||
}
|
||||
result = PyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail);
|
||||
done:
|
||||
|
@ -760,9 +801,16 @@ complex_from_string_inner(const char *s, Py_ssize_t len, void *type)
|
|||
start = s;
|
||||
while (Py_ISSPACE(*s))
|
||||
s++;
|
||||
|
||||
if (*s == '(') {
|
||||
/* Skip over possible bracket from repr(). */
|
||||
got_bracket = 1;
|
||||
}
|
||||
else if (*s == '-' && s[1] == '(') {
|
||||
got_bracket = -1;
|
||||
s++;
|
||||
}
|
||||
if (got_bracket) {
|
||||
/* Skip over possible bracket from repr(). */
|
||||
s++;
|
||||
while (Py_ISSPACE(*s))
|
||||
s++;
|
||||
|
@ -863,6 +911,10 @@ complex_from_string_inner(const char *s, Py_ssize_t len, void *type)
|
|||
if (s-start != len)
|
||||
goto parse_error;
|
||||
|
||||
if (got_bracket < 0) {
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
return complex_subtype_from_doubles((PyTypeObject *)type, x, y);
|
||||
|
||||
parse_error:
|
||||
|
|
Loading…
Reference in New Issue