pub const NON_ROOT_PRIMES: [u8; 4] = [2, 3, 5, 7];
pub const PRIME_PERIOD: u8 = {
let mut product = 1;
let mut i = 0;
while i < NON_ROOT_PRIMES.len() {
product *= NON_ROOT_PRIMES[i];
i += 1;
}
product
};
pub const PRIME_ROOTS: [u8; 48] = {
let mut primes = [0u8; 48];
let mut num = 2;
let mut idx = 0;
while num < PRIME_PERIOD + 2 {
if num % 2 != 0 && num % 3 != 0 && num % 5 != 0 && num % 7 != 0 {
primes[idx] = num;
idx += 1;
}
num += 1;
}
if idx != 48 {
panic!("Prime roots count mismatch");
}
primes
};
pub const NUM_ROOTS: usize = PRIME_ROOTS.len();
pub fn align_to_cycle(start: u128, end: u128) -> (u128, u128) {
let r_min = PRIME_ROOTS[0] as u128; let r_max = PRIME_ROOTS[NUM_ROOTS - 1] as u128;
let b_start = (start.saturating_sub(r_max)).div_ceil(210); let b_end = 1 + (end - r_min) / 210;
(b_start, b_end)
}
pub fn find_inv_prime_root_vec(root_idx: usize) -> Vec<u8> {
let r = PRIME_ROOTS[root_idx] as u32;
PRIME_ROOTS
.iter()
.copied()
.map(|q| {
let period = PRIME_PERIOD as u32;
let q = q as u32;
PRIME_ROOTS
.iter()
.copied()
.find(|&h_candidate| (q * h_candidate as u32) % period == r % period)
.expect("No inverse prime root found")
})
.collect()
}
pub fn get_cyclic_composite_vec(root_index: usize, inv_prime_root_table_row: &[u8]) -> Vec<u8> {
let r = PRIME_ROOTS[root_index] as u32;
let period = PRIME_PERIOD as u32;
PRIME_ROOTS
.iter()
.enumerate()
.map(|(j, &q)| {
let q_hat = inv_prime_root_table_row[j] as u32;
let q = q as u32;
let val = if r > (q * q_hat) {
1 + (period + q * q_hat - r) / period
} else {
1 + (q * q_hat - r) / period
};
val as u8
})
.collect()
}
pub fn get_small_primes(start: u128, end: u128) -> Vec<u128> {
[2, 3, 5, 7]
.iter()
.filter(|&&p| p >= start && p <= end)
.cloned()
.collect()
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ConfigMode {
Sieve,
Window,
MillerRabinDeterministic,
MillerRabinProbabilistic,
}
pub fn get_auto_mode(_start: u128, end: u128) -> ConfigMode {
let big_o_sieve = end.isqrt(); let big_o_miller = end.ilog10().pow(6) as u128;
if big_o_sieve > big_o_miller {
if end > u64::MAX as u128 {
ConfigMode::MillerRabinProbabilistic
} else {
ConfigMode::MillerRabinDeterministic
}
} else {
ConfigMode::Sieve
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constants() {
assert_eq!(NON_ROOT_PRIMES, [2, 3, 5, 7]);
assert_eq!(PRIME_PERIOD, 2 * 3 * 5 * 7);
assert_eq!(PRIME_ROOTS.len(), 48);
for &root in &PRIME_ROOTS {
assert!(root >= 11);
assert!(root <= 211);
assert_ne!(root % 2, 0);
assert_ne!(root % 3, 0);
assert_ne!(root % 5, 0);
assert_ne!(root % 7, 0);
}
}
#[test]
fn test_align_to_cycle() {
assert_eq!(align_to_cycle(0, 210), (0, 1));
assert_eq!(align_to_cycle(210, 420), (0, 2));
assert_eq!(align_to_cycle(100, 200), (0, 1));
assert_eq!(align_to_cycle(300, 500), (1, 3));
assert_eq!(align_to_cycle(211, 211), (0, 1)); assert_eq!(align_to_cycle(13, 13), (0, 1)); }
#[test]
fn test_inverse_prime_roots() {
let first_inverses = find_inv_prime_root_vec(0);
assert_eq!(first_inverses.len(), 48);
let last_inverses = find_inv_prime_root_vec(47);
assert_eq!(last_inverses.len(), 48);
let test_root = PRIME_ROOTS[10]; let inverses = find_inv_prime_root_vec(10);
for (i, &h) in inverses.iter().enumerate() {
let q = PRIME_ROOTS[i];
assert_eq!(
(q as u32 * h as u32) % PRIME_PERIOD as u32,
test_root as u32 % PRIME_PERIOD as u32
);
}
}
#[test]
fn test_cyclic_composites() {
let test_index = PRIME_ROOTS.iter().position(|&r| r == 11).unwrap();
let inverses = find_inv_prime_root_vec(test_index);
let composites = get_cyclic_composite_vec(test_index, &inverses);
assert_eq!(composites.len(), 48);
assert!(composites.iter().all(|&v| v > 0));
}
#[test]
fn test_small_primes() {
assert_eq!(get_small_primes(2, 10), vec![2, 3, 5, 7]);
assert_eq!(get_small_primes(5, 7), vec![5, 7]);
assert!(get_small_primes(8, 10).is_empty());
}
#[test]
fn test_auto_mode_selection() {
assert_eq!(get_auto_mode(0, 1_000), ConfigMode::Sieve);
assert_eq!(
get_auto_mode(0, u128::MAX),
ConfigMode::MillerRabinProbabilistic
);
let borderline = 10u128.pow(15);
let mode = get_auto_mode(0, borderline);
assert!(matches!(
mode,
ConfigMode::Sieve | ConfigMode::MillerRabinDeterministic
));
}
#[test]
fn test_prime_root_validity() {
assert!(PRIME_ROOTS.iter().all(|&r| (11..=211).contains(&r)));
let mut sorted = PRIME_ROOTS.to_vec();
sorted.sort_unstable();
sorted.dedup();
assert_eq!(sorted.len(), 48);
}
#[test]
fn test_boundary_alignment() {
assert_eq!(align_to_cycle(209, 211), (0, 1));
assert_eq!(align_to_cycle(211, 421), (0, 2));
let big_num = 210u128.pow(10);
assert_eq!(
align_to_cycle(big_num, big_num + 100),
(big_num / 210 - 1, big_num / 210 + 1)
);
}
}