From 9717e58ac178c7e4a2a9da9852a7c47744d47084 Mon Sep 17 00:00:00 2001 From: astro Date: Fri, 22 May 2026 23:55:09 -0500 Subject: [PATCH 1/2] Introduce `checked_lcm` and `checked_gcd_lcm` Add `checked_lcm` and `checked_gcd_lcm` as counterparts to existing `lcm` and `gcd_lcm` functions, in which the LCM may be None in the case of overflow. --- src/lib.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5d84a3c..6730f36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,6 +121,18 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// ~~~ fn lcm(&self, other: &Self) -> Self; + /// Lowest Common Multiple (LCM) that returns `None` + /// if the LCM is too big for the type. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(7.checked_lcm(&3), Some(21)); + /// assert_eq!(262144i32.checked_lcm(&262145i32), None); + /// ~~~ + fn checked_lcm(&self, other: &Self) -> Option; + /// Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) together. /// @@ -139,6 +151,25 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { (self.gcd(other), self.lcm(other)) } + /// Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) together, with the LCM returning `None` + /// if the LCM is too big for the type. + /// + /// Potentially more efficient than calling `gcd` and `lcm` + /// individually for identical inputs. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(10.checked_gcd_lcm(&4), (2, Some(20))); + /// assert_eq!(262144i32.checked_gcd_lcm(&262145i32), (1, None)); + /// ~~~ + #[inline] + fn checked_gcd_lcm(&self, other: &Self) -> (Self, Option) { + (self.gcd(other), self.checked_lcm(other)) + } + /// Greatest common divisor and Bézout coefficients. /// /// # Examples @@ -425,6 +456,12 @@ pub fn gcd(x: T, y: T) -> T { pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } +/// Calculates the Lowest Common Multiple (LCM) of the number and `other`, +/// returning `None` if the LCM is too big for the type. +#[inline(always)] +pub fn checked_lcm(x: T, y: T) -> Option { + x.checked_lcm(&y) +} /// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. @@ -433,6 +470,14 @@ pub fn gcd_lcm(x: T, y: T) -> (T, T) { x.gcd_lcm(&y) } +/// Calculates the Greatest Common Divisor (GCD) and +/// Lowest Common Multiple (LCM) of the number and `other`, with the LCM +/// returning `None` if the LCM is too big for the type. +#[inline(always)] +pub fn checked_gcd_lcm(x: T, y: T) -> (T, Option) { + x.checked_gcd_lcm(&y) +} + macro_rules! impl_integer_for_isize { ($T:ty, $test_mod:ident) => { impl Integer for $T { @@ -550,6 +595,13 @@ macro_rules! impl_integer_for_isize { self.gcd_lcm(other).1 } + /// Calculates the Lowest Common Multiple (LCM) of the number and + /// `other`, returning `None` if the LCM is too big for the type. + #[inline] + fn checked_lcm(&self, other: &Self) -> Option { + self.checked_gcd_lcm(other).1 + } + /// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. #[inline] @@ -563,6 +615,21 @@ macro_rules! impl_integer_for_isize { (gcd, lcm) } + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`, with + /// the LCM returning `None` if the LCM is too big for the type. + #[inline] + fn checked_gcd_lcm(&self, other: &Self) -> (Self, Option) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Some(Self::zero())); + } + let gcd = self.gcd(other); + match self.checked_mul(*other / gcd) { + Some(prod) => (gcd, Some(prod.abs())), + None => (gcd, None), + } + } + /// Returns `true` if the number is a multiple of `other`. #[inline] fn is_multiple_of(&self, other: &Self) -> bool { @@ -912,6 +979,13 @@ macro_rules! impl_integer_for_usize { self.gcd_lcm(other).1 } + /// Calculates the Lowest Common Multiple (LCM) of the number and `other`, + /// returning `None` if the LCM is too big for the type. + #[inline] + fn checked_lcm(&self, other: &Self) -> Option { + self.checked_gcd_lcm(other).1 + } + /// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. #[inline] @@ -924,6 +998,21 @@ macro_rules! impl_integer_for_usize { (gcd, lcm) } + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`, with the LCM + /// returning `None` if the LCM is too big for the type. + #[inline] + fn checked_gcd_lcm(&self, other: &Self) -> (Self, Option) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Some(Self::zero())); + } + let gcd = self.gcd(other); + match self.checked_mul(*other / gcd) { + Some(prod) => (gcd, Some(prod)), + None => (gcd, None), + } + } + /// Returns `true` if the number is a multiple of `other`. #[inline] fn is_multiple_of(&self, other: &Self) -> bool { From 186485680a63dc0af703a86d079919bdd4ba9cb0 Mon Sep 17 00:00:00 2001 From: astro Date: Fri, 22 May 2026 23:55:26 -0500 Subject: [PATCH 2/2] Update lib.rs --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6730f36..31bff99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { fn lcm(&self, other: &Self) -> Self; /// Lowest Common Multiple (LCM) that returns `None` - /// if the LCM is too big for the type. + /// if the LCM is too big for the type. /// /// # Examples /// @@ -153,7 +153,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) together, with the LCM returning `None` - /// if the LCM is too big for the type. + /// if the LCM is too big for the type. /// /// Potentially more efficient than calling `gcd` and `lcm` /// individually for identical inputs. @@ -617,7 +617,7 @@ macro_rules! impl_integer_for_isize { /// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`, with - /// the LCM returning `None` if the LCM is too big for the type. + /// the LCM returning `None` if the LCM is too big for the type. #[inline] fn checked_gcd_lcm(&self, other: &Self) -> (Self, Option) { if self.is_zero() && other.is_zero() { @@ -980,7 +980,7 @@ macro_rules! impl_integer_for_usize { } /// Calculates the Lowest Common Multiple (LCM) of the number and `other`, - /// returning `None` if the LCM is too big for the type. + /// returning `None` if the LCM is too big for the type. #[inline] fn checked_lcm(&self, other: &Self) -> Option { self.checked_gcd_lcm(other).1 @@ -1000,7 +1000,7 @@ macro_rules! impl_integer_for_usize { /// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`, with the LCM - /// returning `None` if the LCM is too big for the type. + /// returning `None` if the LCM is too big for the type. #[inline] fn checked_gcd_lcm(&self, other: &Self) -> (Self, Option) { if self.is_zero() && other.is_zero() {