Skip to content

Commit

Permalink
Print real part for complex even if it's zero
Browse files Browse the repository at this point in the history
* adapt Lib/test/test_format.py and Lib/test/test_complex.py
* adjust doctests
  • Loading branch information
skirpichev committed Oct 1, 2024
1 parent 737293b commit db12274
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 19 deletions.
4 changes: 2 additions & 2 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ are always available. They are listed here in alphabetical order.
>>> complex('+1.23')
(1.23+0j)
>>> complex('-4.5j')
-4.5j
(0.0-4.5j)
>>> complex('-1.23+4.5j')
(-1.23+4.5j)
>>> complex('\t( -1.23+4.5J )\n')
Expand All @@ -399,7 +399,7 @@ are always available. They are listed here in alphabetical order.
>>> complex(1.23)
(1.23+0j)
>>> complex(imag=-4.5)
-4.5j
(0.0-4.5j)
>>> complex(-1.23, 4.5)
(-1.23+4.5j)

Expand Down
27 changes: 19 additions & 8 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,9 +819,13 @@ def test(v, expected, test_fn=self.assertEqual):
test(complex(NAN, NAN), "(nan+nanj)")
test(complex(-NAN, -NAN), "(nan+nanj)")

test(complex(0, INF), "infj")
test(complex(0, -INF), "-infj")
test(complex(0, NAN), "nanj")
test(complex(0, INF), "(0.0+infj)")
test(complex(0, -INF), "(0.0-infj)")
test(complex(0, NAN), "(0.0+nanj)")

test(imaginary(INF), "infj")
test(imaginary(-INF), "-infj")
test(imaginary(NAN), "nanj")

self.assertEqual(1-6j,complex(repr(1-6j)))
self.assertEqual(1+6j,complex(repr(1+6j)))
Expand All @@ -834,16 +838,22 @@ def test(v, expected, test_fn=self.assertEqual):
test_fn(repr(v), expected)
test_fn(str(v), expected)

test(complex(0., 1.), "1j")
test(complex(0., 1.), "(0.0+1j)")
test(complex(-0., 1.), "(-0.0+1j)")
test(complex(0., -1.), "-1j")
test(complex(0., -1.), "(0.0-1j)")
test(complex(-0., -1.), "(-0.0-1j)")

test(complex(0., 0.), "0j")
test(complex(0., -0.), "-0j")
test(imaginary(+1.), "1j")
test(imaginary(-1.), "-1j")

test(complex(0., 0.), "(0.0+0j)")
test(complex(0., -0.), "(0.0-0j)")
test(complex(-0., 0.), "(-0.0+0j)")
test(complex(-0., -0.), "(-0.0-0j)")

test(imaginary(+0.0), "0j")
test(imaginary(-0.0), "-0j")

def test_pos(self):
self.assertEqual(+(1+6j), 1+6j)
self.assertEqual(+ComplexSubclass(1, 6), 1+6j)
Expand Down Expand Up @@ -950,7 +960,8 @@ def test_format(self):
self.assertEqual(format(z, '3'), str(z))

self.assertEqual(format(1+3j, 'g'), '1+3j')
self.assertEqual(format(3j, 'g'), '0+3j')
self.assertEqual(format(0+3j, 'g'), '0.0+3j')
self.assertEqual(format(3j, 'g'), '3j')
self.assertEqual(format(1.5+3.5j, 'g'), '1.5+3.5j')

self.assertEqual(format(1.5+3.5j, '+g'), '+1.5+3.5j')
Expand Down
13 changes: 9 additions & 4 deletions Lib/test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,15 @@ def test_negative_zero(self):
self.assertEqual(f"{-1.:+z.0f}", "-1")
self.assertEqual(f"{-1.:-z.0f}", "-1")

self.assertEqual(f"{0.j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{-0.j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{.01j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{-.01j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{0.0+0.j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{0.0-0.j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{0.0+.01j:z.1f}", "0.0+0.0j")
self.assertEqual(f"{0.0-.01j:z.1f}", "0.0+0.0j")

self.assertEqual(f"{0.j:z.1f}", "0.0j")
self.assertEqual(f"{-0.j:z.1f}", "0.0j")
self.assertEqual(f"{.01j:z.1f}", "0.0j")
self.assertEqual(f"{-.01j:z.1f}", "0.0j")

self.assertEqual(f"{-0.:z>6.1f}", "zz-0.0") # test fill, esp. 'z' fill
self.assertEqual(f"{-0.:z>z6.1f}", "zzz0.0")
Expand Down
5 changes: 2 additions & 3 deletions Objects/complexobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,9 +463,8 @@ complex_repr(PyComplexObject *v)
const char *lead = "";
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 (PyImaginary_Check(v)) {
/* Just output the imaginary part and do not include parens. */
re = "";
im = PyOS_double_to_string(v->cval.imag, format_code,
precision, 0, NULL);
Expand Down
8 changes: 6 additions & 2 deletions Python/formatter_unicode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,7 @@ format_complex_internal(PyObject *value,
/* Omitted type specifier. Should be like str(self). */
type = 'r';
default_precision = 0;
if (re == 0.0 && copysign(1.0, re) == 1.0)
if (PyImaginary_Check(value))
skip_re = 1;
else
add_parens = 1;
Expand All @@ -1290,10 +1290,14 @@ format_complex_internal(PyObject *value,
/* Cast "type", because if we're in unicode we need to pass an
8-bit char. This is safe, because we've restricted what "type"
can be. */
if (re == 0.0 && copysign(1.0, re) == -1.0)
if (re == 0.0) {
if (PyImaginary_Check(value)) {
skip_re = 1;
}
re_buf = PyOS_double_to_string(re, (char)type, precision,
flags | Py_DTSF_ADD_DOT_0,
&re_float_type);
}
else
re_buf = PyOS_double_to_string(re, (char)type, precision, flags,
&re_float_type);
Expand Down

0 comments on commit db12274

Please sign in to comment.