diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index 4547fee..c12137d 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -46,6 +46,27 @@ pub trait Euclid: Sized + Div + Rem { /// assert_eq!(Euclid::rem_euclid(&-a, &-b), 1); /// ``` fn rem_euclid(&self, v: &Self) -> Self; + + /// Returns both the quotient and remainder from Euclidean division. + /// + /// By default, it internally calls both `Euclid::div_euclid` and `Euclid::rem_euclid`, + /// but it can be overridden in order to implement some optimization. + /// + /// # Examples + /// + /// ``` + /// # use num_traits::Euclid; + /// let x = 5u8; + /// let y = 3u8; + /// + /// let div = Euclid::div_euclid(&x, &y); + /// let rem = Euclid::rem_euclid(&x, &y); + /// + /// assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y)); + /// ``` + fn div_rem_euclid(&self, v: &Self) -> (Self, Self) { + (self.div_euclid(v), self.rem_euclid(v)) + } } macro_rules! euclid_forward_impl { @@ -174,6 +195,26 @@ pub trait CheckedEuclid: Euclid { /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and /// division by zero. If any of that happens, `None` is returned. fn checked_rem_euclid(&self, v: &Self) -> Option; + + /// Returns both the quotient and remainder from checked Euclidean division. + /// + /// By default, it internally calls both `CheckedEuclid::checked_div_euclid` and `CheckedEuclid::checked_rem_euclid`, + /// but it can be overridden in order to implement some optimization. + /// # Examples + /// + /// ``` + /// # use num_traits::CheckedEuclid; + /// let x = 5u8; + /// let y = 3u8; + /// + /// let div = CheckedEuclid::checked_div_euclid(&x, &y); + /// let rem = CheckedEuclid::checked_rem_euclid(&x, &y); + /// + /// assert_eq!(Some((div.unwrap(), rem.unwrap())), CheckedEuclid::checked_div_rem_euclid(&x, &y)); + /// ``` + fn checked_div_rem_euclid(&self, v: &Self) -> Option<(Self, Self)> { + Some((self.checked_div_euclid(v)?, self.checked_rem_euclid(v)?)) + } } macro_rules! checked_euclid_forward_impl { @@ -262,8 +303,11 @@ mod tests { { let x: $t = 10; let y: $t = 3; - assert_eq!(Euclid::div_euclid(&x, &y), 3); - assert_eq!(Euclid::rem_euclid(&x, &y), 1); + let div = Euclid::div_euclid(&x, &y); + let rem = Euclid::rem_euclid(&x, &y); + assert_eq!(div, 3); + assert_eq!(rem, 1); + assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y)); } )+ }; @@ -284,6 +328,7 @@ mod tests { assert_eq!(Euclid::div_euclid(&-x, &y), 4); assert_eq!(Euclid::rem_euclid(&x, &y), 1); assert_eq!(Euclid::rem_euclid(&-x, &y), 2); + assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y)); let x: $t = $t::min_value() + 1; let y: $t = -1; assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value()); @@ -311,6 +356,7 @@ mod tests { <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); + assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y)); } )+ };