From 72eebbfd35ad02cba2edbcb4131f35fd1b876961 Mon Sep 17 00:00:00 2001 From: Elliott Mahler Date: Tue, 6 Feb 2024 08:26:16 -0800 Subject: [PATCH] Re-added function that appeared unused, and re-added default features --- Cargo.toml | 2 +- src/math_utils.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 120acab..f267ee2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ categories = ["algorithms", "compression", "multimedia::encoding", "science"] license = "MIT OR Apache-2.0" [features] -default = [] +default = ["avx", "sse", "neon"] # On x86_64, the "avx" feature enables compilation of AVX-acclerated code. # Similarly, the "sse" feature enables compilation of SSE-accelerated code. diff --git a/src/math_utils.rs b/src/math_utils.rs index 128b666..57d1cd2 100644 --- a/src/math_utils.rs +++ b/src/math_utils.rs @@ -190,6 +190,52 @@ impl PrimeFactors { self.power_three > 0 && self.power_two == 0 && self.other_factors.len() == 0 } + // Divides the number by the given prime factor. Returns None if the resulting number is one. + #[allow(unused)] + pub fn remove_factors(mut self, factor: PrimeFactor) -> Option { + if factor.count == 0 { + return Some(self); + } + if factor.value == 2 { + self.power_two = self.power_two.checked_sub(factor.count).unwrap(); + self.n >>= factor.count; + self.total_factor_count -= factor.count; + if self.power_two == 0 { + self.distinct_factor_count -= 1; + } + if self.n > 1 { + return Some(self); + } + } else if factor.value == 3 { + self.power_three = self.power_three.checked_sub(factor.count).unwrap(); + self.n /= 3.pow(factor.count); + self.total_factor_count -= factor.count; + if self.power_two == 0 { + self.distinct_factor_count -= 1; + } + if self.n > 1 { + return Some(self); + } + } else { + let found_factor = self + .other_factors + .iter_mut() + .find(|item| item.value == factor.value) + .unwrap(); + found_factor.count = found_factor.count.checked_sub(factor.count).unwrap(); + self.n /= factor.value.pow(factor.count); + self.total_factor_count -= factor.count; + if found_factor.count == 0 { + self.distinct_factor_count -= 1; + self.other_factors.retain(|item| item.value != factor.value); + } + if self.n > 1 { + return Some(self); + } + } + None + } + // returns true if we have any factors whose value is less than or equal to the provided factor pub fn has_factors_leq(&self, factor: usize) -> bool { self.power_two > 0 @@ -653,6 +699,28 @@ mod unit_tests { } } + #[test] + fn test_remove_factors() { + // For every possible factor of a bunch of factors, they removing each and making sure the result is internally consistent + for n in 2..200 { + let factors = PrimeFactors::compute(n); + + for i in 0..=factors.get_power_of_two() { + if let Some(removed_factors) = factors + .clone() + .remove_factors(PrimeFactor { value: 2, count: i }) + { + assert_eq!(removed_factors.get_product(), factors.get_product() >> i); + assert_internally_consistent(&removed_factors); + } else { + // If the method returned None, this must be a power of two and i must be equal to the product + assert!(n.is_power_of_two()); + assert!(i == factors.get_power_of_two()); + } + } + } + } + #[test] fn test_partial_factors() { #[derive(Debug)]