diff --git a/src/lib.rs b/src/lib.rs index 41e0139..0c20d5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,6 +95,21 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// ~~~ fn lcm(&self, other: &Self) -> Self; + /// Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) simultaneously. + /// + /// More efficient than calling `gcd` and `lcm` + /// individually for identical inputs. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(10.gcd_lcm(&4), (2, 20)); + /// assert_eq!(8.gcd_lcm(&9), (1, 72)); + /// ~~~ + fn gcd_lcm(&self, other: &Self) -> (Self, Self); + /// Deprecated, use `is_multiple_of` instead. fn divides(&self, other: &Self) -> bool; @@ -206,6 +221,13 @@ pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } +/// Calculates the Greatest Common Divisor (GCD) and +/// Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] +pub fn gcd_lcm(x: T, y: T) -> (T, T) { + x.gcd_lcm(&y) +} + macro_rules! impl_integer_for_isize { ($T:ty, $test_mod:ident) => ( impl Integer for $T { @@ -297,6 +319,16 @@ macro_rules! impl_integer_for_isize { (*self * (*other / self.gcd(other))).abs() } + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + let gcd = self.gcd(other); + // should not have to recalculate abs + let lcm = (*self * (*other / gcd)).abs(); + (gcd, lcm) + } + /// Deprecated, use `is_multiple_of` instead. #[inline] fn divides(&self, other: &Self) -> bool { @@ -475,6 +507,15 @@ macro_rules! impl_integer_for_isize { assert_eq!((11 as $T).lcm(&5), 55 as $T); } + #[test] + fn test_gcd_lcm() { + for i in 1..=255 { + for j in 0..=255 { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + #[test] fn test_even() { assert_eq!((-4 as $T).is_even(), true); @@ -560,6 +601,15 @@ macro_rules! impl_integer_for_usize { *self * (*other / self.gcd(other)) } + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + let gcd = self.gcd(other); + let lcm = *self * (*other / gcd); + (gcd, lcm) + } + /// Deprecated, use `is_multiple_of` instead. #[inline] fn divides(&self, other: &Self) -> bool { @@ -653,6 +703,15 @@ macro_rules! impl_integer_for_usize { assert_eq!((15 as $T).lcm(&17), 255 as $T); } + #[test] + fn test_gcd_lcm() { + for i in 1..=255 { + for j in 0..=255 { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + #[test] fn test_is_multiple_of() { assert!((6 as $T).is_multiple_of(&(6 as $T)));