mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Compare complex with int exactly instead of through a float (#9180)
complex.__eq__ and __ne__ converted an int operand to f64 before comparing, so a complex whose real part is the float nearest to a large int compared equal to that int even when the values differ: complex(2**53 + 1) == 2**53 + 1 returned True, while float(2**53 + 1) == 2**53 + 1 returns False and the two objects hash differently. When the imaginary part is zero, compare the real part against the exact integer with float_ops::eq_int, the helper float's own comparison uses. This matches CPython, which hands an int operand to float's rich comparison. test_complex.test_richcompare_boundaries now passes, so drop its expectedFailure marker. Assisted-by: Claude Code:claude-opus-5-5
This commit is contained in:
1 parent
cf6ca56789
commit
9fd2ba8367
2 files changed
+12
-10
No files matched your search
Vendored
-1
@@ -244,7 +244,6 @@ class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
||||
self.assertIs(operator.ne(1+1j, 2+2j), True)
|
||||
self.assertIs(operator.eq(1+1j, 2.0), False)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: True is not False
|
||||
def test_richcompare_boundaries(self):
|
||||
def check(n, deltas, is_equal, imag = 0.0):
|
||||
for delta in deltas:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::{PyStr, PyType, PyTypeRef, float};
|
||||
use super::{PyInt, PyStr, PyType, PyTypeRef, float};
|
||||
use crate::{
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::PyUtf8StrRef,
|
||||
class::{PyClassDef, PyClassImpl},
|
||||
common::wtf8::Wtf8Buf,
|
||||
common::{float_ops, wtf8::Wtf8Buf},
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
function::{FuncArgs, OptionalArg, PyComparisonValue},
|
||||
protocol::PyNumberMethods,
|
||||
@@ -623,17 +623,20 @@ impl Comparable for PyComplex {
|
||||
zelf: &Py<Self>,
|
||||
other: &PyObject,
|
||||
op: PyComparisonOp,
|
||||
vm: &VirtualMachine,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyResult<PyComparisonValue> {
|
||||
op.eq_only(|| {
|
||||
let value = zelf.as_complex();
|
||||
let result = if let Some(other) = other.downcast_ref::<Self>() {
|
||||
zelf.as_complex() == other.as_complex()
|
||||
value == other.as_complex()
|
||||
} else if let Some(other) = other.downcast_ref::<PyInt>() {
|
||||
// Compare with the exact integer, as float does, instead of
|
||||
// rounding the integer to the nearest float first.
|
||||
value.im == 0.0 && float_ops::eq_int(value.re, other.as_bigint())
|
||||
} else if let Some(other) = other.downcast_ref::<float::PyFloat>() {
|
||||
value == other.to_f64().into()
|
||||
} else {
|
||||
match float::to_op_float(other, vm) {
|
||||
Ok(Some(other)) => zelf.as_complex() == other.into(),
|
||||
Err(_) => false,
|
||||
Ok(None) => return Ok(PyComparisonValue::NotImplemented),
|
||||
}
|
||||
return Ok(PyComparisonValue::NotImplemented);
|
||||
};
|
||||
Ok(PyComparisonValue::Implemented(result))
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user