use crate::math::sieve_of_eratosthenes;
use num_bigint::BigUint;
use num_traits::One;
use std::collections::BTreeMap;
fn index(p: usize, n: usize) -> usize {
let mut index = 0;
let mut i = 1;
let mut quot = n / p;
while quot > 0 {
index += quot;
i += 1;
quot = n / p.pow(i);
}
index
}
pub fn fast_factorial(n: usize) -> BigUint {
if n < 2 {
return BigUint::one();
}
let primes = sieve_of_eratosthenes(n);
let mut p_indeces = BTreeMap::new();
primes.into_iter().for_each(|p| {
p_indeces.insert(p, index(p, n));
});
let max_bits = p_indeces.get(&2).unwrap().next_power_of_two().ilog2();
let mut a = Vec::with_capacity(max_bits as usize);
a.resize(max_bits as usize, BigUint::one());
for (p, i) in p_indeces.into_iter() {
let mut bit = 1usize;
while bit.ilog2() < max_bits {
if (bit & i) > 0 {
a[bit.ilog2() as usize] *= p;
}
bit <<= 1;
}
}
a.into_iter()
.enumerate()
.map(|(i, a_i)| a_i.pow(2u32.pow(i as u32)))
.product()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::big_integer::hello_bigmath::factorial;
#[test]
fn fact() {
assert_eq!(fast_factorial(30), factorial(30));
assert_eq!(fast_factorial(52), factorial(52));
assert_eq!(fast_factorial(100), factorial(100));
assert_eq!(fast_factorial(1000), factorial(1000));
assert_eq!(fast_factorial(5000), factorial(5000));
}
}