From dea6c93a0b64be8bd423ff5b4e567d6910835503 Mon Sep 17 00:00:00 2001 From: dot Date: Tue, 3 Nov 2026 20:49:17 +0900 Subject: [PATCH 1/2] Fix integer-to-float overflow rounding boundary Preserve the nearest finite result until the actual halfway overflow threshold for integer division and integer-to-float conversion. Assisted-by: OpenAI Codex:model version not exposed --- crates/common/src/int.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/crates/common/src/int.rs b/crates/common/src/int.rs index f0e84d9b730..d787b18678c 100644 --- a/crates/common/src/int.rs +++ b/crates/common/src/int.rs @@ -6,13 +6,10 @@ use num_traits::{One, ToPrimitive, Zero}; #[must_use] pub fn true_div(numerator: &BigInt, denominator: &BigInt) -> f64 { let rational = Rational::from_integers_ref(numerator.into(), denominator.into()); - match rational.rounding_into(RoundingMode::Nearest) { - // returned value is $t::MAX but still less than the original - (val, core::cmp::Ordering::Less) if val == f64::MAX => f64::INFINITY, - // returned value is $t::MIN but still greater than the original - (val, core::cmp::Ordering::Greater) if val == f64::MIN => f64::NEG_INFINITY, - (val, _) => val, - } + // Nearest rounding can return the largest finite value for a quotient + // slightly beyond it; overflow starts at the halfway rounding boundary. + let (rounded, _) = rational.rounding_into(RoundingMode::Nearest); + rounded } #[must_use] @@ -202,11 +199,16 @@ fn word_all_ascii_digits(word: u64) -> bool { (below | above) & 0x8080_8080_8080_8080 == 0 } -// num-bigint now returns Some(inf) for to_f64() in some cases, so just keep that the same for now +/// Convert an integer to a finite float, or return None when it overflows. #[inline(always)] #[must_use] pub fn bigint_to_finite_float(int: &BigInt) -> Option { - int.to_f64().filter(|f| f.is_finite()) + // malachite-bigint's ToPrimitive returns None when the input exceeds + // the largest finite magnitude, even when nearest rounding is finite. + let value = int + .to_f64() + .unwrap_or_else(|| true_div(int, &BigInt::one())); + value.is_finite().then_some(value) } #[cfg(test)] From 4fd589aa40b5e3160284e3a9902d9a5f97418809 Mon Sep 17 00:00:00 2001 From: dot Date: Wed, 4 Nov 2026 01:10:06 +0900 Subject: [PATCH 2/2] Retire passing float conversion expected failure Assisted-by: OpenAI Codex:model version not exposed --- Lib/test/test_long.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 0241616e292..73739323bd5 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -403,7 +403,6 @@ def check_float_conversion(self, n): "Got {}, expected {}.".format(n, actual, expected)) self.assertEqual(actual, expected, msg) - @unittest.expectedFailure # TODO: RUSTPYTHON @support.requires_IEEE_754 def test_float_conversion(self):