pub fn primes_up_to(n: usize) -> Vec<u64> {
if n < 2 {
return Vec::new();
}
let mut is_prime = vec![true; n + 1];
is_prime[0] = false;
is_prime[1] = false;
let mut i = 2usize;
while i * i <= n {
if is_prime[i] {
let mut j = i * i;
while j <= n {
is_prime[j] = false;
j += i;
}
}
i += 1;
}
(2..=n)
.filter(|&i| is_prime[i])
.map(|i| i as u64)
.collect()
}
pub fn first_n_primes(n: usize) -> Vec<u64> {
if n == 0 {
return Vec::new();
}
if n < 6 {
return primes_up_to(15).into_iter().take(n).collect();
}
let nf = n as f64;
let mut limit = (nf * (nf.ln() + nf.ln().ln()) * 1.3).ceil() as usize;
loop {
let primes = primes_up_to(limit);
if primes.len() >= n {
return primes.into_iter().take(n).collect();
}
limit *= 2;
}
}
pub fn factorize(mut n: u64) -> Vec<(u64, u32)> {
let mut factors = Vec::new();
if n < 2 {
return factors;
}
let mut d = 2u64;
while d * d <= n {
if n % d == 0 {
let mut exp = 0u32;
while n % d == 0 {
n /= d;
exp += 1;
}
factors.push((d, exp));
}
d += if d == 2 { 1 } else { 2 };
}
if n > 1 {
factors.push((n, 1));
}
factors
}
pub fn radical(n: u64) -> u64 {
if n == 0 {
return 0;
}
factorize(n)
.into_iter()
.map(|(p, _)| p)
.product::<u64>()
.max(1)
}
pub fn distinct_primes(n: u64) -> Vec<u64> {
factorize(n).into_iter().map(|(p, _)| p).collect()
}
pub fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
pub fn lcm(a: u64, b: u64) -> u64 {
if a == 0 || b == 0 {
return 0;
}
a / gcd(a, b) * b
}
pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
return (a.abs(), if a < 0 { -1 } else { 1 }, 0);
}
let (g, x, y) = extended_gcd(b, a % b);
(g, y, x - (a / b) * y)
}
pub fn mod_inverse(a: u64, m: u64) -> Option<u64> {
if m == 0 {
return None;
}
if m == 1 {
return Some(0);
}
let (g, x, _) = extended_gcd((a % m) as i64, m as i64);
if g != 1 {
return None;
}
let m_i = m as i64;
Some((((x % m_i) + m_i) % m_i) as u64)
}
pub fn termination_period(n: u64, base: u64) -> Option<u64> {
if n == 0 || base < 2 {
return None;
}
let mut coprime_part = n;
loop {
let g = gcd(coprime_part, base);
if g == 1 {
break;
}
coprime_part /= g;
}
if coprime_part == 1 {
return Some(0); }
let b = base % coprime_part;
let mut order = 1u64;
let mut acc = b % coprime_part;
while acc != 1 {
acc = (acc * b) % coprime_part;
order += 1;
}
Some(order)
}
pub fn natural_base(denominators: &[u64]) -> u64 {
denominators
.iter()
.filter(|&&d| d != 0)
.map(|&d| radical(d))
.fold(1u64, lcm)
.max(1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sieve_basic() {
assert_eq!(primes_up_to(11), vec![2, 3, 5, 7, 11]);
assert!(primes_up_to(1).is_empty());
}
#[test]
fn first_n() {
assert_eq!(first_n_primes(5), vec![2, 3, 5, 7, 11]);
let p = first_n_primes(32);
assert_eq!(p.len(), 32);
assert_eq!(*p.last().unwrap(), 131); }
#[test]
fn factor() {
assert_eq!(factorize(12), vec![(2, 2), (3, 1)]);
assert_eq!(factorize(13), vec![(13, 1)]);
assert!(factorize(1).is_empty());
}
#[test]
fn radicals() {
assert_eq!(radical(12), 6);
assert_eq!(radical(1), 1);
assert_eq!(radical(30), 30);
}
#[test]
fn gcd_lcm() {
assert_eq!(gcd(12, 18), 6);
assert_eq!(lcm(4, 6), 12);
}
#[test]
fn egcd_and_inverse() {
let (g, x, y) = extended_gcd(240, 46);
assert_eq!(g, 2);
assert_eq!(240 * x + 46 * y, 2);
assert_eq!(mod_inverse(3, 11), Some(4)); assert_eq!(mod_inverse(2, 4), None);
}
#[test]
fn termination() {
assert_eq!(termination_period(8, 10), Some(0)); assert_eq!(termination_period(3, 10), Some(1)); assert_eq!(termination_period(7, 10), Some(6)); assert_eq!(termination_period(6, 10), Some(1)); }
#[test]
fn nat_base() {
assert_eq!(natural_base(&[6, 10, 15]), 30);
assert_eq!(natural_base(&[12]), 6);
}
}