use crate::{gcd, newtons_method};
use num_traits::{ConstOne, ConstZero, PrimInt, ToPrimitive};
#[cfg_attr(doc, katexit::katexit)]
pub fn pcf<T>(x: T) -> f64
where
T: ToPrimitive,
{
let x = x.to_f64().expect("Cannot convert x to f64.");
if x < 0.0 {
panic!("x must be non-negative.");
} else if x < 2.0 {
0.0
} else if x < 3.0 {
1.0
} else if x < 5.0 {
2.0
} else if x < 7.0 {
3.0
} else if x < 11.0 {
4.0
} else {
x / x.ln()
}
}
#[cfg_attr(doc, katexit::katexit)]
pub fn apcf<T>(n: T) -> f64
where
T: ToPrimitive,
{
let mut n = n.to_f64().expect("Cannot convert n to f64.");
if n < 0.0 {
panic!("n must be non-negative.");
} else if n <= 3.0 {
n = n.floor();
match n {
0.0 => 0.0,
1.0 => 2.0,
2.0 => 3.0,
3.0 => 5.0,
_ => unreachable!(),
}
} else {
let x0 = n + 1.0;
let precision = 1e-10;
let function = |x: f64| n * x.ln() - x;
let derivative = |x: f64| n / x - 1.0;
newtons_method(x0, precision, function, derivative).unwrap()
}
}
pub fn coprime<T>(a: T, b: T) -> bool
where
T: PrimInt + ConstZero + ConstOne,
{
gcd(a, b) == T::ONE
}
pub fn is_prime<T>(n: T) -> (bool, T)
where
T: PrimInt + ConstZero + ConstOne,
{
let t2 = T::from(2).unwrap();
if n < t2 {
panic!("n must be greater than or equal to 2.");
}
let t3 = T::from(3).unwrap();
let t6 = T::from(6).unwrap();
if n == t2 || n == t3 {
(true, T::ONE)
} else if n % t2 == T::ZERO {
(false, t2)
} else if n % t3 == T::ZERO {
(false, t3)
} else {
let upper_bound =
T::from(n.to_f64().expect("Cannot convert n to f64.").sqrt().floor()).unwrap();
let mut i = T::from(5).unwrap();
while i <= upper_bound {
if n % i == T::ZERO {
return (false, i);
} else if n % (i + t2) == T::ZERO {
return (false, i + t2);
}
i = i + t6; }
(true, T::ONE)
}
}
pub fn sieve_of_eratosthenes<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstOne,
{
let t2 = T::from(2).unwrap();
if n < t2 {
Vec::with_capacity(0)
} else if n == t2 {
vec![t2]
} else {
let mut results = vec![t2];
let mut sieve = vec![true; ((n - T::ONE) / t2).to_usize().expect("Sieve too large.")];
let ind_to_val = |i: usize| ((i as u64) << 1) + 3; let val_to_ind = |v: u64| ((v - 3) >> 1) as usize;
for prime_ind in 0..sieve.len() {
if sieve[prime_ind] {
let prime_val = ind_to_val(prime_ind);
let prime_val_2 = prime_val << 1;
let mut check_val = prime_val * prime_val;
let mut check_ind = val_to_ind(check_val);
if check_ind >= sieve.len() {
break;
}
while check_ind < sieve.len() {
sieve[check_ind] = false;
check_val += prime_val_2;
check_ind = val_to_ind(check_val);
}
}
}
results.extend(sieve.into_iter().enumerate().filter_map(|(i, prime)| {
if prime {
Some(T::from(ind_to_val(i)).unwrap())
} else {
None
}
}));
results
}
}