From 6cbf4472420c2858dc576ab16f77abcf0bf0be22 Mon Sep 17 00:00:00 2001 From: may Date: Fri, 5 Sep 2025 20:28:06 +0200 Subject: [PATCH 1/2] implement round_ties_even for Ratio --- src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b1cf2a4..f13d9e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,6 +257,46 @@ impl Ratio { } } + /// Rounds to the nearest integer. Rounds half-way cases to even. + pub fn round_ties_even(&self) -> Ratio { + let zero: Ratio = Zero::zero(); + let one: T = One::one(); + let two: T = one.clone() + one.clone(); + + // Find unsigned fractional part of rational number + let mut fractional = self.fract(); + if fractional < zero { + fractional = zero - fractional + }; + + // Compare the unsigned fractional part with 1/2 + let half = Ratio::new_raw(one, two); + match fractional.cmp(&half) { + cmp::Ordering::Greater => { + let one: Ratio = One::one(); + if *self >= Zero::zero() { + self.trunc() + one + } else { + self.trunc() - one + } + } + cmp::Ordering::Equal => { + let trunc = self.trunc(); + if trunc.numer().is_even() { + trunc + } else { + let one: Ratio = One::one(); + if *self >= Zero::zero() { + self.trunc() + one + } else { + self.trunc() - one + } + } + } + cmp::Ordering::Less => self.trunc(), + } + } + /// Rounds towards zero. #[inline] pub fn trunc(&self) -> Ratio { From 797bd6e1f1135d87d4bc57c834b50bdc7401d063 Mon Sep 17 00:00:00 2001 From: may Date: Fri, 5 Sep 2025 20:28:21 +0200 Subject: [PATCH 2/2] add some tests for round_ties_even --- src/lib.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f13d9e9..19c8969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1782,6 +1782,7 @@ mod test { pub const _0: Rational64 = Ratio { numer: 0, denom: 1 }; pub const _1: Rational64 = Ratio { numer: 1, denom: 1 }; pub const _2: Rational64 = Ratio { numer: 2, denom: 1 }; + pub const _3: Rational64 = Ratio { numer: 3, denom: 1 }; pub const _NEG2: Rational64 = Ratio { numer: -2, denom: 1, @@ -2690,38 +2691,51 @@ mod test { assert_eq!(_1_3.ceil(), _1); assert_eq!(_1_3.floor(), _0); assert_eq!(_1_3.round(), _0); + assert_eq!(_1_3.round_ties_even(), _0); assert_eq!(_1_3.trunc(), _0); assert_eq!(_NEG1_3.ceil(), _0); assert_eq!(_NEG1_3.floor(), -_1); assert_eq!(_NEG1_3.round(), _0); + assert_eq!(_NEG1_3.round_ties_even(), _0); assert_eq!(_NEG1_3.trunc(), _0); assert_eq!(_2_3.ceil(), _1); assert_eq!(_2_3.floor(), _0); assert_eq!(_2_3.round(), _1); + assert_eq!(_2_3.round_ties_even(), _1); assert_eq!(_2_3.trunc(), _0); assert_eq!(_NEG2_3.ceil(), _0); assert_eq!(_NEG2_3.floor(), -_1); assert_eq!(_NEG2_3.round(), -_1); + assert_eq!(_NEG2_3.round_ties_even(), -_1); assert_eq!(_NEG2_3.trunc(), _0); assert_eq!(_1_2.ceil(), _1); assert_eq!(_1_2.floor(), _0); assert_eq!(_1_2.round(), _1); + assert_eq!(_1_2.round_ties_even(), _0); assert_eq!(_1_2.trunc(), _0); assert_eq!(_NEG1_2.ceil(), _0); assert_eq!(_NEG1_2.floor(), -_1); assert_eq!(_NEG1_2.round(), -_1); + assert_eq!(_NEG1_2.round_ties_even(), _0); assert_eq!(_NEG1_2.trunc(), _0); assert_eq!(_1.ceil(), _1); assert_eq!(_1.floor(), _1); assert_eq!(_1.round(), _1); + assert_eq!(_1.round_ties_even(), _1); assert_eq!(_1.trunc(), _1); + assert_eq!(_5_2.ceil(), _3); + assert_eq!(_5_2.floor(), _2); + assert_eq!(_5_2.round(), _3); + assert_eq!(_5_2.round_ties_even(), _2); + assert_eq!(_5_2.trunc(), _2); + // Overflow checks let _neg1 = Ratio::from_integer(-1); @@ -2742,6 +2756,14 @@ mod test { assert_eq!(_large_rat6.round(), _neg1); assert_eq!(_large_rat7.round(), Zero::zero()); assert_eq!(_large_rat8.round(), Zero::zero()); + assert_eq!(_large_rat1.round_ties_even(), One::one()); + assert_eq!(_large_rat2.round_ties_even(), One::one()); + assert_eq!(_large_rat3.round_ties_even(), One::one()); + assert_eq!(_large_rat4.round_ties_even(), One::one()); + assert_eq!(_large_rat5.round_ties_even(), _neg1); + assert_eq!(_large_rat6.round_ties_even(), _neg1); + assert_eq!(_large_rat7.round_ties_even(), Zero::zero()); + assert_eq!(_large_rat8.round_ties_even(), Zero::zero()); } #[test]