mirror of https://github.com/python/cpython.git
Issue #8748: Fix incorrect results from comparisons between an integer
and a complex instance. Based on a patch by Meador Inge.
This commit is contained in:
parent
4b3035d0b8
commit
4ca7c3c089
|
@ -129,7 +129,7 @@ def __cmp__(self, other):
|
||||||
self.assertTrue(a < 2.0j)
|
self.assertTrue(a < 2.0j)
|
||||||
|
|
||||||
def test_richcompare(self):
|
def test_richcompare(self):
|
||||||
self.assertRaises(OverflowError, complex.__eq__, 1+1j, 1L<<10000)
|
self.assertEqual(complex.__eq__(1+1j, 1L<<10000), False)
|
||||||
self.assertEqual(complex.__lt__(1+1j, None), NotImplemented)
|
self.assertEqual(complex.__lt__(1+1j, None), NotImplemented)
|
||||||
self.assertIs(complex.__eq__(1+1j, 1+1j), True)
|
self.assertIs(complex.__eq__(1+1j, 1+1j), True)
|
||||||
self.assertIs(complex.__eq__(1+1j, 2+2j), False)
|
self.assertIs(complex.__eq__(1+1j, 2+2j), False)
|
||||||
|
@ -140,6 +140,23 @@ def test_richcompare(self):
|
||||||
self.assertRaises(TypeError, complex.__gt__, 1+1j, 2+2j)
|
self.assertRaises(TypeError, complex.__gt__, 1+1j, 2+2j)
|
||||||
self.assertRaises(TypeError, complex.__ge__, 1+1j, 2+2j)
|
self.assertRaises(TypeError, complex.__ge__, 1+1j, 2+2j)
|
||||||
|
|
||||||
|
def test_richcompare_boundaries(self):
|
||||||
|
def check(n, deltas, is_equal, imag = 0.0):
|
||||||
|
for delta in deltas:
|
||||||
|
i = n + delta
|
||||||
|
z = complex(i, imag)
|
||||||
|
self.assertIs(complex.__eq__(z, i), is_equal(delta))
|
||||||
|
self.assertIs(complex.__ne__(z, i), not is_equal(delta))
|
||||||
|
# For IEEE-754 doubles the following should hold:
|
||||||
|
# x in [2 ** (52 + i), 2 ** (53 + i + 1)] -> x mod 2 ** i == 0
|
||||||
|
# where the interval is representable, of course.
|
||||||
|
for i in range(1, 10):
|
||||||
|
pow = 52 + i
|
||||||
|
mult = 2 ** i
|
||||||
|
check(2 ** pow, range(1, 101), lambda delta: delta % mult == 0)
|
||||||
|
check(2 ** pow, range(1, 101), lambda delta: False, float(i))
|
||||||
|
check(2 ** 53, range(-100, 0), lambda delta: True)
|
||||||
|
|
||||||
def test_mod(self):
|
def test_mod(self):
|
||||||
self.assertRaises(ZeroDivisionError, (1+1j).__mod__, 0+0j)
|
self.assertRaises(ZeroDivisionError, (1+1j).__mod__, 0+0j)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,13 @@ What's New in Python 2.7 Release Candidate 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #8748: Fix two issues with comparisons between complex and integer
|
||||||
|
objects. (1) The comparison could incorrectly return True in some cases
|
||||||
|
(2**53+1 == complex(2**53) == 2**53), breaking transivity of equality.
|
||||||
|
(2) The comparison raised an OverflowError for large integers, leading
|
||||||
|
to unpredictable exceptions when combining integers and complex objects
|
||||||
|
in sets or dicts.
|
||||||
|
|
||||||
- Issue #5211: Implicit coercion for the complex type is now completely
|
- Issue #5211: Implicit coercion for the complex type is now completely
|
||||||
removed. (Coercion for arithmetic operations was already removed in 2.7
|
removed. (Coercion for arithmetic operations was already removed in 2.7
|
||||||
alpha 4, but coercion for rich comparisons was accidentally left in.)
|
alpha 4, but coercion for rich comparisons was accidentally left in.)
|
||||||
|
|
|
@ -783,25 +783,70 @@ complex_coerce(PyObject **pv, PyObject **pw)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
complex_richcompare(PyObject *v, PyObject *w, int op)
|
complex_richcompare(PyObject *v, PyObject *w, int op)
|
||||||
{
|
{
|
||||||
Py_complex i, j;
|
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
Py_complex i;
|
||||||
TO_COMPLEX(v, i);
|
int equal;
|
||||||
TO_COMPLEX(w, j);
|
|
||||||
|
|
||||||
if (op != Py_EQ && op != Py_NE) {
|
if (op != Py_EQ && op != Py_NE) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
/* for backwards compatibility, comparisons with non-numbers return
|
||||||
"no ordering relation is defined for complex numbers");
|
* NotImplemented. Only comparisons with core numeric types raise
|
||||||
return NULL;
|
* TypeError.
|
||||||
|
*/
|
||||||
|
if (PyInt_Check(w) || PyLong_Check(w) ||
|
||||||
|
PyFloat_Check(w) || PyComplex_Check(w)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"no ordering relation is defined "
|
||||||
|
"for complex numbers");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
goto Unimplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((i.real == j.real && i.imag == j.imag) == (op == Py_EQ))
|
assert(PyComplex_Check(v));
|
||||||
res = Py_True;
|
TO_COMPLEX(v, i);
|
||||||
|
|
||||||
|
if (PyInt_Check(w) || PyLong_Check(w)) {
|
||||||
|
/* Check for 0.0 imaginary part first to avoid the rich
|
||||||
|
* comparison when possible.
|
||||||
|
*/
|
||||||
|
if (i.imag == 0.0) {
|
||||||
|
PyObject *j, *sub_res;
|
||||||
|
j = PyFloat_FromDouble(i.real);
|
||||||
|
if (j == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sub_res = PyObject_RichCompare(j, w, op);
|
||||||
|
Py_DECREF(j);
|
||||||
|
return sub_res;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
equal = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (PyFloat_Check(w)) {
|
||||||
|
equal = (i.real == PyFloat_AsDouble(w) && i.imag == 0.0);
|
||||||
|
}
|
||||||
|
else if (PyComplex_Check(w)) {
|
||||||
|
Py_complex j;
|
||||||
|
|
||||||
|
TO_COMPLEX(w, j);
|
||||||
|
equal = (i.real == j.real && i.imag == j.imag);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto Unimplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equal == (op == Py_EQ))
|
||||||
|
res = Py_True;
|
||||||
else
|
else
|
||||||
res = Py_False;
|
res = Py_False;
|
||||||
|
|
||||||
Py_INCREF(res);
|
Py_INCREF(res);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
Unimplemented:
|
||||||
|
Py_INCREF(Py_NotImplemented);
|
||||||
|
return Py_NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Reference in New Issue