diff --git a/src/ops.rs b/src/ops.rs index 8efd1e8..30a6f74 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) => { @@ -273,6 +273,17 @@ checked_arith_impl!(impl CheckedAdd, checked_add); // a/b - c/d = (lcm/b*a - lcm/d*c)/lcm, where lcm = lcm(b,d) checked_arith_impl!(impl CheckedSub, checked_sub); +// -(a/b) = (-a)/b, so only the numerator can overflow +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 Neg for Ratio where T: Clone + Integer + Neg, diff --git a/src/tests/arith.rs b/src/tests/arith.rs index 7bd310b..39845b0 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,15 @@ fn test_neg() { test(_1_2, _NEG1_2); test(-_1, _1); } + +#[test] +fn test_checked_neg() { + assert_eq!(_0.checked_neg(), Some(_0)); + assert_eq!(_1_2.checked_neg(), Some(_NEG1_2)); + assert_eq!(_NEG1_2.checked_neg(), Some(_1_2)); + // Negating the numerator i64::MIN overflows. + assert_eq!(Ratio::new(i64::MIN, 3).checked_neg(), None); +} #[test] #[allow(clippy::eq_op)] fn test_zero() {