use crate::error::{Error, Result};
const MAX_FACTORS: usize = 40;
pub fn is_prime(n: u32) -> bool {
if n <= 1 {
return false;
} else if n <= 3 {
return true;
} else if n % 2 == 0 {
return false; } else if n % 3 == 0 {
return false; }
let mut r = 5;
while r * r <= n {
if n % r == 0 || n % (r + 2) == 0 {
return false;
}
r += 6;
}
true
}
pub fn factor(n: u32, factors: &mut Vec<u32>) -> Result<usize> {
let mut num = n;
let mut num_factors = 0;
while num > 1 && num_factors < MAX_FACTORS {
for k in 2..=num {
if num % k == 0 {
factors.push(k);
num_factors += 1;
num /= k;
break;
}
}
}
if num > 1 && num_factors == MAX_FACTORS {
return Err(Error::NoConvergence("could not factor number in MAX_FACTORS numbers".to_string()));
}
factors.shrink_to_fit();
Ok(num_factors)
}
pub fn unique_factor(n: u32, factors: &mut Vec<u32>) -> Result<usize> {
let mut num = n;
let mut num_factors = 0;
while num > 1 && num_factors < MAX_FACTORS {
for k in 2..=num {
if num % k == 0 {
if num_factors == 0 || factors[num_factors - 1] != k {
factors.push(k);
num_factors += 1;
}
num /= k;
break;
}
}
}
if num > 1 && num_factors == MAX_FACTORS {
return Err(Error::NoConvergence("could not factor number in MAX_FACTORS numbers".to_string()));
}
Ok(num_factors)
}
pub fn gcd(mut p: u32, mut q: u32) -> Result<u32> {
if p == 0 || q == 0 {
return Err(Error::Value("input cannot be zero".to_string()));
} else if p == 1 || q == 1 {
return Ok(1);
} else if p == q {
return Ok(p);
} else if p < q {
return gcd(q, p);
}
let mut gcd = 1;
let mut r = 2; while r <= q {
while p % r == 0 && q % r == 0 {
p /= r;
q /= r;
gcd *= r;
}
r += if r == 2 { 1 } else { 2 };
}
Ok(gcd)
}
pub fn modpow(base: u32, exp: u32, n: u32) -> u32 {
let mut c = 1;
for _ in 0..exp {
c = (c * base) % n;
}
c
}
pub fn primitive_root(_n: u32) -> u32 {
unimplemented!()
}
pub fn primitive_root_prime(n: u32) -> Result<u32> {
let mut unique_factors = Vec::with_capacity(MAX_FACTORS);
let num_unique_factors = unique_factor(n - 1, &mut unique_factors).unwrap();
for g in 2..n {
let mut is_root = true;
for &factor in &unique_factors[0..num_unique_factors] {
let e = (n - 1) / factor;
if modpow(g, e, n) == 1 {
is_root = false;
break;
}
}
if is_root {
return Ok(g);
}
}
Err(Error::Value("No primitive root found for prime".to_string()))
}
pub fn totient(x: u32) -> u32 {
let mut t = x;
let mut n = x;
let mut p = 0;
loop {
for k in 2..=n {
if n % k == 0 {
n /= k;
if p != k {
t *= k - 1;
t /= k;
}
p = k;
break;
}
}
if n < 2 {
break;
}
}
t
}
#[cfg(test)]
mod tests {
use super::*;
use test_macro::autotest_annotate;
#[test]
#[autotest_annotate(autotest_prime_small)]
fn test_prime_small() {
for (n, &expected_is_prime) in IS_PRIME_ARRAY.iter().enumerate() {
assert_eq!(is_prime(n as u32), expected_is_prime != 0);
}
}
#[test]
#[autotest_annotate(autotest_factors)]
fn test_factors() {
const FACTORS_280: [u32; 5] = [2, 2, 2, 5, 7];
const FACTORS_280_UNIQUE: [u32; 3] = [2, 5, 7];
let mut factors = Vec::with_capacity(MAX_FACTORS);
let num_factors = factor(280, &mut factors).unwrap();
assert_eq!(num_factors, 5);
assert_eq!(factors, FACTORS_280);
let mut factors = Vec::with_capacity(MAX_FACTORS);
let num_unique_factors = unique_factor(280, &mut factors).unwrap();
assert_eq!(num_unique_factors, 3);
assert_eq!(factors, FACTORS_280_UNIQUE);
}
#[test]
#[autotest_annotate(autotest_totient)]
fn test_totient() {
assert_eq!(totient(9), 6);
assert_eq!(totient(20), 8);
assert_eq!(totient(100), 40);
assert_eq!(totient(1200), 320);
assert_eq!(totient(1201), 1200);
}
fn testbench_gcd(gcd_expected: u32, p: u32, q: u32) {
let p = p * gcd_expected;
let q = q * gcd_expected;
let gcd_test = gcd(p, q).unwrap();
assert_eq!(gcd_test, gcd_expected, "gcd({}, {}) = {} (expected {})", p, q, gcd_test, gcd_expected);
}
#[test]
#[autotest_annotate(autotest_gcd_one)]
fn test_gcd_one() {
testbench_gcd(1, 2, 3);
testbench_gcd(1, 2, 5);
testbench_gcd(1, 2, 7);
testbench_gcd(1, 7, 2);
testbench_gcd(1, 17, 19);
testbench_gcd(1, 23, 31);
testbench_gcd(1, 2*2*2*2*2, 3*5*7*19);
}
#[test]
#[autotest_annotate(autotest_gcd_edge_cases)]
fn test_gcd_edge_cases() {
testbench_gcd(1, 1, 1);
testbench_gcd(1, 1, 2);
testbench_gcd(1, 1, 2400);
testbench_gcd(12345, 1, 1); testbench_gcd((1<<17)-1, 1, 1); }
#[test]
#[autotest_annotate(autotest_gcd_base)]
fn test_gcd_base() {
testbench_gcd(2*2*3*5*7, 2*3, 17);
testbench_gcd(2*2*3*5*7, 2*3, 17*17);
testbench_gcd(2*2*3*5*7, 2*3, 17*17*17);
testbench_gcd(11, 3, 1);
testbench_gcd(3, 127, 131);
testbench_gcd(131, 127, 3);
testbench_gcd(127, 131, 3);
}
#[test]
fn test_modpow() {
assert_eq!(modpow(2, 3, 5), 3);
assert_eq!(modpow(3, 4, 7), 4);
}
#[test]
fn test_primitive_root_prime() {
assert_eq!(primitive_root_prime(5).unwrap(), 2);
assert_eq!(primitive_root_prime(7).unwrap(), 3);
}
const IS_PRIME_ARRAY: [u8; 2500] = [
0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,
0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,
0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,
0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,
0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,
0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,
0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,
0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,
0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,
0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,
0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,
0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,
0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
];
}