pub(super) const LIMIT: usize = 1 << 13;
pub(super) const COUNT: usize = count();
const fn sieve() -> [bool; LIMIT / 2] {
let mut composite = [false; LIMIT / 2];
composite[0] = true;
let mut i = 1;
while (2 * i + 1) * (2 * i + 1) < LIMIT {
if !composite[i] {
let p = 2 * i + 1;
let mut j = p * p / 2;
while j < LIMIT / 2 {
composite[j] = true;
j += p;
}
}
i += 1;
}
composite
}
const fn count() -> usize {
let composite = sieve();
let mut n = 0;
let mut i = 0;
while i < LIMIT / 2 {
if !composite[i] {
n += 1;
}
i += 1;
}
n
}
#[derive(Clone, Copy)]
pub(super) struct Prime {
pub(super) p: u64,
pub(super) inv: u64,
pub(super) max: u64,
}
impl Prime {
#[inline(always)]
pub(super) fn divides(&self, x: u64) -> bool {
x.wrapping_mul(self.inv) <= self.max
}
}
const fn binvert(d: u64) -> u64 {
let mut v = d.wrapping_mul(3) ^ 2;
let mut i = 0;
while i < 4 {
v = v.wrapping_mul(2u64.wrapping_sub(d.wrapping_mul(v)));
i += 1;
}
v
}
pub(super) static PRIMES: [Prime; COUNT] = primes();
const fn primes() -> [Prime; COUNT] {
let composite = sieve();
let mut primes = [Prime {
p: 0,
inv: 0,
max: 0,
}; COUNT];
let (mut i, mut n) = (0, 0);
while i < LIMIT / 2 {
if !composite[i] {
let p = (2 * i + 1) as u64;
primes[n] = Prime {
p,
inv: binvert(p),
max: u64::MAX / p,
};
n += 1;
}
i += 1;
}
primes
}
#[derive(Clone, Copy)]
pub(super) struct Group {
pub(super) first: u16,
pub(super) end: u16,
pub(super) d: u64,
pub(super) v: u64,
}
pub(super) const GROUPS: usize = {
let primes = primes();
let (mut g, mut i) = (0, 0);
while i < COUNT {
let mut product = 1u64;
while i < COUNT {
match product.checked_mul(primes[i].p) {
Some(x) => product = x,
None => break,
}
i += 1;
}
g += 1;
}
g
};
pub(super) static GROUP: [Group; GROUPS] = groups();
const fn groups() -> [Group; GROUPS] {
let primes = primes();
let mut groups = [Group {
first: 0,
end: 0,
d: 0,
v: 0,
}; GROUPS];
let (mut g, mut i) = (0, 0);
while i < COUNT {
let first = i;
let mut product = 1u64;
while i < COUNT {
match product.checked_mul(primes[i].p) {
Some(x) => product = x,
None => break,
}
i += 1;
}
let d = product << product.leading_zeros();
groups[g] = Group {
first: first as u16,
end: i as u16,
d,
v: (u128::MAX / d as u128) as u64,
};
g += 1;
}
groups
}
pub(super) fn groups_below(bound: u64) -> usize {
let mut g = 0;
while g < GROUPS && PRIMES[GROUP[g].end as usize - 1].p < bound {
g += 1;
}
g
}