use super::mod_pow;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PrimePowerFactorization {
pub prime: u32,
pub exponent: u32,
}
impl PrimePowerFactorization {
#[must_use]
pub fn value(&self) -> u64 {
(self.prime as u64).pow(self.exponent)
}
}
#[must_use]
pub fn is_prime(n: u32) -> bool {
if n < 2 {
return false;
}
if n == 2 || n == 3 {
return true;
}
if n % 2 == 0 {
return false;
}
if n < 9 {
return true;
}
if n % 3 == 0 {
return false;
}
let witnesses: &[u64] = &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];
let n_minus_1 = (n - 1) as u64;
let r = n_minus_1.trailing_zeros();
let d = n_minus_1 >> r;
'witness: for &a in witnesses {
if a >= n as u64 {
continue;
}
let mut x = mod_pow(a, d, n as u64);
if x == 1 || x == n_minus_1 {
continue 'witness;
}
for _ in 0..(r - 1) {
x = x.wrapping_mul(x) % (n as u64);
if x == n_minus_1 {
continue 'witness;
}
}
return false;
}
true
}
#[must_use]
pub fn is_prime_power(n: u32) -> bool {
factor_prime_power(n).is_some()
}
#[must_use]
pub fn factor_prime_power(n: u32) -> Option<PrimePowerFactorization> {
if n < 2 {
return None;
}
if is_prime(n) {
return Some(PrimePowerFactorization {
prime: n,
exponent: 1,
});
}
if n.is_power_of_two() {
return Some(PrimePowerFactorization {
prime: 2,
exponent: n.trailing_zeros(),
});
}
let max_exp = 32 - n.leading_zeros();
for k in 2..=max_exp {
if let Some(root) = integer_kth_root(n as u64, k) {
let root = root as u32;
if root > 1 && is_prime(root) {
if root.checked_pow(k).map_or(false, |v| v == n) {
return Some(PrimePowerFactorization {
prime: root,
exponent: k,
});
}
}
}
}
None
}
fn integer_kth_root(n: u64, k: u32) -> Option<u64> {
if k == 0 {
return None;
}
if n == 0 {
return Some(0);
}
if k == 1 {
return Some(n);
}
if n == 1 {
return Some(1);
}
let bits = 64 - n.leading_zeros();
let mut x = 1u64 << ((bits + k - 1) / k);
loop {
let x_pow_k_minus_1 = match x.checked_pow(k - 1) {
Some(v) => v,
None => {
x /= 2;
continue;
}
};
if x_pow_k_minus_1 == 0 {
return Some(x);
}
let n_div_x_pow = n / x_pow_k_minus_1;
let new_x = ((k as u64 - 1) * x + n_div_x_pow) / (k as u64);
if new_x >= x {
if let Some(x_pow_k) = x.checked_pow(k) {
if x_pow_k == n {
return Some(x);
}
}
return None;
}
x = new_x;
}
}
#[must_use]
pub fn smallest_prime_factor(n: u32) -> Option<u32> {
if n < 2 {
return None;
}
if n % 2 == 0 {
return Some(2);
}
let sqrt_n = (n as f64).sqrt() as u32 + 1;
let mut i = 3;
while i <= sqrt_n {
if n % i == 0 {
return Some(i);
}
i += 2;
}
Some(n)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_prime() {
assert!(is_prime(2));
assert!(is_prime(3));
assert!(is_prime(5));
assert!(is_prime(7));
assert!(is_prime(11));
assert!(is_prime(13));
assert!(is_prime(17));
assert!(is_prime(19));
assert!(is_prime(23));
assert!(!is_prime(0));
assert!(!is_prime(1));
assert!(!is_prime(4));
assert!(!is_prime(6));
assert!(!is_prime(8));
assert!(!is_prime(9));
assert!(!is_prime(10));
assert!(!is_prime(100));
assert!(is_prime(97));
assert!(is_prime(101));
assert!(is_prime(1009));
assert!(is_prime(10007));
assert!(is_prime(100003));
assert!(!is_prime(561)); assert!(!is_prime(1105)); assert!(!is_prime(1729)); }
#[test]
fn test_is_prime_power() {
assert!(is_prime_power(2));
assert!(is_prime_power(4));
assert!(is_prime_power(8));
assert!(is_prime_power(16));
assert!(is_prime_power(32));
assert!(is_prime_power(64));
assert!(is_prime_power(3));
assert!(is_prime_power(9));
assert!(is_prime_power(27));
assert!(is_prime_power(81));
assert!(is_prime_power(5));
assert!(is_prime_power(25));
assert!(is_prime_power(125));
assert!(is_prime_power(7));
assert!(is_prime_power(11));
assert!(is_prime_power(13));
assert!(!is_prime_power(0));
assert!(!is_prime_power(1));
assert!(!is_prime_power(6)); assert!(!is_prime_power(10)); assert!(!is_prime_power(12)); assert!(!is_prime_power(15)); assert!(!is_prime_power(18)); assert!(!is_prime_power(20)); }
#[test]
fn test_factor_prime_power() {
assert_eq!(
factor_prime_power(8),
Some(PrimePowerFactorization {
prime: 2,
exponent: 3
})
);
assert_eq!(
factor_prime_power(9),
Some(PrimePowerFactorization {
prime: 3,
exponent: 2
})
);
assert_eq!(
factor_prime_power(16),
Some(PrimePowerFactorization {
prime: 2,
exponent: 4
})
);
assert_eq!(
factor_prime_power(27),
Some(PrimePowerFactorization {
prime: 3,
exponent: 3
})
);
assert_eq!(
factor_prime_power(7),
Some(PrimePowerFactorization {
prime: 7,
exponent: 1
})
);
assert_eq!(
factor_prime_power(125),
Some(PrimePowerFactorization {
prime: 5,
exponent: 3
})
);
assert_eq!(factor_prime_power(0), None);
assert_eq!(factor_prime_power(1), None);
assert_eq!(factor_prime_power(6), None);
assert_eq!(factor_prime_power(12), None);
}
#[test]
fn test_smallest_prime_factor() {
assert_eq!(smallest_prime_factor(0), None);
assert_eq!(smallest_prime_factor(1), None);
assert_eq!(smallest_prime_factor(2), Some(2));
assert_eq!(smallest_prime_factor(3), Some(3));
assert_eq!(smallest_prime_factor(4), Some(2));
assert_eq!(smallest_prime_factor(6), Some(2));
assert_eq!(smallest_prime_factor(9), Some(3));
assert_eq!(smallest_prime_factor(15), Some(3));
assert_eq!(smallest_prime_factor(17), Some(17));
assert_eq!(smallest_prime_factor(35), Some(5));
}
#[test]
fn test_prime_power_factorization_value() {
let f = PrimePowerFactorization {
prime: 2,
exponent: 10,
};
assert_eq!(f.value(), 1024);
let f = PrimePowerFactorization {
prime: 3,
exponent: 5,
};
assert_eq!(f.value(), 243);
}
}