Skip to content

Commit 280e312

Browse files
author
guido.van.rossum
committed
Patch # 1507 by Mark Dickinson. Make complex(x, -0) retain the sign of
the imaginary part (as long as it's not complex). Backport candidate? git-svn-id: http://svn.python.org/projects/python/trunk@59203 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent fa85c56 commit 280e312

2 files changed

Lines changed: 28 additions & 9 deletions

File tree

Lib/test/test_complex.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
)
1010

1111
from random import random
12+
from math import atan2
1213

1314
# These tests ensure that complex math does the right thing
1415

@@ -225,6 +226,18 @@ class complex2(complex): pass
225226
self.assertAlmostEqual(complex(real=17+23j, imag=23), 17+46j)
226227
self.assertAlmostEqual(complex(real=1+2j, imag=3+4j), -3+5j)
227228

229+
# check that the sign of a zero in the real or imaginary part
230+
# is preserved when constructing from two floats. (These checks
231+
# are harmless on systems without support for signed zeros.)
232+
def split_zeros(x):
233+
"""Function that produces different results for 0. and -0."""
234+
return atan2(x, -1.)
235+
236+
self.assertEqual(split_zeros(complex(1., 0.).imag), split_zeros(0.))
237+
self.assertEqual(split_zeros(complex(1., -0.).imag), split_zeros(-0.))
238+
self.assertEqual(split_zeros(complex(0., 1.).real), split_zeros(0.))
239+
self.assertEqual(split_zeros(complex(-0., 1.).real), split_zeros(-0.))
240+
228241
c = 3.14 + 1j
229242
self.assert_(complex(c) is c)
230243
del c

Objects/complexobject.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,8 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
897897
PyNumberMethods *nbr, *nbi = NULL;
898898
Py_complex cr, ci;
899899
int own_r = 0;
900+
int cr_is_complex = 0;
901+
int ci_is_complex = 0;
900902
static PyObject *complexstr;
901903
static char *kwlist[] = {"real", "imag", 0};
902904

@@ -977,6 +979,7 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
977979
retaining its real & imag parts here, and the return
978980
value is (properly) of the builtin complex type. */
979981
cr = ((PyComplexObject*)r)->cval;
982+
cr_is_complex = 1;
980983
if (own_r) {
981984
Py_DECREF(r);
982985
}
@@ -985,7 +988,6 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
985988
/* The "real" part really is entirely real, and contributes
986989
nothing in the imaginary direction.
987990
Just treat it as a double. */
988-
cr.imag = 0.0;
989991
tmp = PyNumber_Float(r);
990992
if (own_r) {
991993
/* r was a newly created complex number, rather
@@ -1005,27 +1007,31 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
10051007
}
10061008
if (i == NULL) {
10071009
ci.real = 0.0;
1008-
ci.imag = 0.0;
10091010
}
1010-
else if (PyComplex_Check(i))
1011+
else if (PyComplex_Check(i)) {
10111012
ci = ((PyComplexObject*)i)->cval;
1012-
else {
1013+
ci_is_complex = 1;
1014+
} else {
10131015
/* The "imag" part really is entirely imaginary, and
10141016
contributes nothing in the real direction.
10151017
Just treat it as a double. */
1016-
ci.imag = 0.0;
10171018
tmp = (*nbi->nb_float)(i);
10181019
if (tmp == NULL)
10191020
return NULL;
10201021
ci.real = PyFloat_AsDouble(tmp);
10211022
Py_DECREF(tmp);
10221023
}
10231024
/* If the input was in canonical form, then the "real" and "imag"
1024-
parts are real numbers, so that ci.real and cr.imag are zero.
1025+
parts are real numbers, so that ci.imag and cr.imag are zero.
10251026
We need this correction in case they were not real numbers. */
1026-
cr.real -= ci.imag;
1027-
cr.imag += ci.real;
1028-
return complex_subtype_from_c_complex(type, cr);
1027+
1028+
if (ci_is_complex) {
1029+
cr.real -= ci.imag;
1030+
}
1031+
if (cr_is_complex) {
1032+
ci.real += cr.imag;
1033+
}
1034+
return complex_subtype_from_doubles(type, cr.real, ci.real);
10291035
}
10301036

10311037
PyDoc_STRVAR(complex_doc,

0 commit comments

Comments
 (0)