self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 0+0j)
def test_richcompare(self):
- self.assertRaises(OverflowError, complex.__eq__, 1+1j, 1<<10000)
+ self.assertIs(complex.__eq__(1+1j, 1<<10000), False)
self.assertIs(complex.__lt__(1+1j, None), NotImplemented)
self.assertIs(complex.__eq__(1+1j, 1+1j), True)
self.assertIs(complex.__eq__(1+1j, 2+2j), False)
self.assertIs(complex.__ne__(1+1j, 1+1j), False)
self.assertIs(complex.__ne__(1+1j, 2+2j), True)
+ for i in range(1, 100):
+ f = i / 100.0
+ self.assertIs(complex.__eq__(f+0j, f), True)
+ self.assertIs(complex.__ne__(f+0j, f), False)
+ self.assertIs(complex.__eq__(complex(f, f), f), False)
+ self.assertIs(complex.__ne__(complex(f, f), f), True)
self.assertIs(complex.__lt__(1+1j, 2+2j), NotImplemented)
self.assertIs(complex.__le__(1+1j, 2+2j), NotImplemented)
self.assertIs(complex.__gt__(1+1j, 2+2j), NotImplemented)
self.assertIs(operator.ne(1+1j, 1+1j), False)
self.assertIs(operator.ne(1+1j, 2+2j), True)
+ 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):
# % is no longer supported on complex numbers
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
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 #8748: Fix comparisons between complex and integer objects.
+ These used to convert the integer object to a complex number before
+ doing the comparison, giving a potentially incorrect result when
+ that conversion involved precision loss. (Ex: 2**53+1 ==
+ complex(2**53) returned True; now returns False.)
+
- Issue #8766: Initialize _warnings module before importing the first module.
Fix a crash if an empty directory called "encodings" exists in sys.path.
complex_richcompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
- Py_complex i, j;
- TO_COMPLEX(v, i);
- TO_COMPLEX(w, j);
+ Py_complex i;
+ int equal;
if (op != Py_EQ && op != Py_NE) {
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
+ goto Unimplemented;
}
- if ((i.real == j.real && i.imag == j.imag) == (op == Py_EQ))
- res = Py_True;
+ assert(PyComplex_Check(v));
+ TO_COMPLEX(v, i);
+
+ if (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
- res = Py_False;
+ res = Py_False;
Py_INCREF(res);
return res;
+
+Unimplemented:
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
}
static PyObject *