diff --git a/src/ops.rs b/src/ops.rs index 8efd1e8..68ecc96 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -7,7 +7,7 @@ use super::Ratio; use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; use num_integer::Integer; -use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Inv, One, Zero}; +use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, Inv, One, Zero}; macro_rules! forward_ref_ref_binop { (impl $imp:ident, $method:ident) => { @@ -297,6 +297,19 @@ where } } +impl CheckedNeg for Ratio +where + T: Clone + Integer + CheckedNeg, +{ + #[inline] + fn checked_neg(&self) -> Option> { + Some(Ratio::new_raw( + self.numer.checked_neg()?, + self.denom.clone(), + )) + } +} + impl Inv for Ratio where T: Clone + Integer, diff --git a/src/tests/arith.rs b/src/tests/arith.rs index 7bd310b..96c91df 100644 --- a/src/tests/arith.rs +++ b/src/tests/arith.rs @@ -2,7 +2,7 @@ use super::super::{Ratio, Rational64}; use super::{to_big, _0, _1, _1_2, _2, _3_2, _5_2, _MAX, _MAX_M1, _MIN, _MIN_P1, _NEG1_2}; use core::fmt::Debug; use num_integer::Integer; -use num_traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, NumAssign}; +use num_traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, NumAssign}; #[test] fn test_add() { @@ -398,6 +398,42 @@ fn test_neg() { test(_1_2, _NEG1_2); test(-_1, _1); } + +#[test] +fn test_checked_neg() { + fn checked(value: Ratio) -> Option> + where + T: Clone + Integer + CheckedNeg, + { + value.checked_neg() + } + + assert_eq!(checked(Ratio::new(i64::MIN, 3)), None); + assert_eq!(checked(Ratio::new_raw(i64::MIN, 3)), None); + assert_eq!(checked(_1_2), Some(_NEG1_2)); + assert_eq!(checked(_NEG1_2), Some(_1_2)); + assert_eq!(checked(_0), Some(_0)); + assert_eq!(checked(_MAX), Some(Ratio::new(-i64::MAX, 1))); + + assert_eq!(checked(Ratio::new(0_u64, 2)), Some(Ratio::new_raw(0, 1))); + assert_eq!(checked(Ratio::new(1_u64, 2)), None); + + let unreduced = Ratio::new_raw(2_i64, 4); + let unreduced_negated = checked(unreduced).unwrap(); + assert_eq!(unreduced_negated.numer(), &-2); + assert_eq!(unreduced_negated.denom(), &4); + + let negative_denominator = Ratio::new_raw(2_i64, -4); + let negative_denominator_negated = checked(negative_denominator).unwrap(); + assert_eq!(negative_denominator_negated.numer(), &-2); + assert_eq!(negative_denominator_negated.denom(), &-4); + + let minimum_denominator = Ratio::new_raw(1_i64, i64::MIN); + let minimum_denominator_negated = checked(minimum_denominator).unwrap(); + assert_eq!(minimum_denominator_negated.numer(), &-1); + assert_eq!(minimum_denominator_negated.denom(), &i64::MIN); +} + #[test] #[allow(clippy::eq_op)] fn test_zero() {