use crate::natural::arithmetic::mul::product_of_limbs::limbs_product;
use crate::natural::arithmetic::mul::{
limbs_mul_greater_to_out, limbs_mul_greater_to_out_scratch_len,
};
use crate::natural::arithmetic::square::{limbs_square_to_out, limbs_square_to_out_scratch_len};
use crate::natural::{LIMB_MAX_DIV_3, Natural, bit_to_limb_count_floor};
use crate::platform::{
Limb, NTH_ROOT_NUMB_MASK_TABLE, ODD_DOUBLEFACTORIAL_TABLE_LIMIT, ODD_DOUBLEFACTORIAL_TABLE_MAX,
ODD_FACTORIAL_TABLE_LIMIT, ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE, ONE_LIMB_ODD_FACTORIAL_TABLE,
TABLE_2N_MINUS_POPC_2N, TABLE_LIMIT_2N_MINUS_POPC_2N,
};
use alloc::vec::Vec;
use malachite_base::fail_on_untested_path;
use malachite_base::num::arithmetic::traits::{
AddMul, AddMulAssign, DoubleFactorial, Factorial, Gcd, Multifactorial, Parity, Pow, PowerOf2,
Square, Subfactorial, XMulYToZZ,
};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{One, Zero};
use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom, WrappingFrom};
#[cfg(feature = "32_bit_limbs")]
use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u32;
#[cfg(not(feature = "32_bit_limbs"))]
use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u64;
use malachite_base::num::factorization::prime_sieve::{id_to_n, limbs_prime_sieve_size, n_to_bit};
use malachite_base::num::logic::traits::{BitAccess, CountOnes, NotAssign, SignificantBits};
const ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1: usize = ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1;
private_test_fn! {subfactorial_naive(n: u64) -> Natural {
let mut f = Natural::ONE;
let mut b = true;
for i in 1..=n {
f *= Natural::from(i);
if b {
f -= Natural::ONE;
} else {
f += Natural::ONE;
}
b.not_assign();
}
f
}}
const SUBFACTORIAL_SPLIT_LEAF_PAIRS: u64 = 32;
const SUBFACTORIAL_SPLIT_THRESHOLD: u64 = 1024;
fn subfactorial_split(lo: u64, hi: u64) -> (Natural, Natural) {
let pairs = ((hi - lo) >> 1) + 1;
if pairs <= SUBFACTORIAL_SPLIT_LEAF_PAIRS {
let mut a = Natural::ONE;
let mut b = Natural::ZERO;
for i in 0..pairs {
let k = lo + (i << 1);
let m = Natural::from(u128::from(k) * u128::from(k + 1));
a *= &m;
b *= m;
b += Natural::from(k);
}
(a, b)
} else {
let mid = lo + ((pairs - (pairs >> 1)) << 1);
let (a_lo, b_lo) = subfactorial_split(lo, mid - 2);
let (a_hi, mut b_hi) = subfactorial_split(mid, hi);
let a = &a_hi * a_lo;
b_hi.add_mul_assign(a_hi, b_lo);
(a, b_hi)
}
}
fn subfactorial_split_only_b(lo: u64, hi: u64) -> Natural {
let pairs = ((hi - lo) >> 1) + 1;
if pairs <= SUBFACTORIAL_SPLIT_LEAF_PAIRS {
let mut b = Natural::ZERO;
for i in 0..pairs {
let k = lo + (i << 1);
b *= Natural::from(u128::from(k) * u128::from(k + 1));
b += Natural::from(k);
}
b
} else {
let mid = lo + ((pairs - (pairs >> 1)) << 1);
let b_lo = subfactorial_split_only_b(lo, mid - 2);
let (a_hi, b_hi) = subfactorial_split(mid, hi);
b_hi.add_mul(a_hi, b_lo)
}
}
fn limbs_approx_sqrt(x: u64) -> u64 {
assert!(x > 2);
let s = x.significant_bits() >> 1;
(u64::power_of_2(s) + (x >> s)) >> 1
}
pub(crate) const fn bit_to_n(bit: u64) -> u64 {
(bit * 3 + 4) | 1
}
#[allow(clippy::useless_conversion)]
fn limbs_2_multiswing_odd(
x_and_sieve: &mut [Limb],
x_len: usize,
mut n: Limb,
factors: &mut [Limb],
) -> usize {
assert!(n > 25);
let mut prod = if n.odd() { n } else { 1 };
n.clear_bit(0);
let max_prod = Limb::MAX / (n - 1);
let mut j = 0;
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = 1;
}
let mut q = n;
while q >= 3 {
q /= 3;
if q.odd() {
prod *= 3;
}
}
let limb_n = n;
let n = u64::exact_from(n);
let mut s = limbs_approx_sqrt(n);
assert!(s >= 5);
s = n_to_bit(s);
assert!(bit_to_n(s + 1).square() > n);
assert!(s < n_to_bit(n / 3));
let start = const { n_to_bit(5) };
let mut index = bit_to_limb_count_floor(start);
let mut mask = Limb::power_of_2(start & Limb::WIDTH_MASK);
let sieve = &mut x_and_sieve[x_len..];
for i in start + 1..=s + 1 {
if sieve[index] & mask == 0 {
let prime = Limb::exact_from(id_to_n(i));
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = 1;
}
let mut q = limb_n;
while q >= prime {
q /= prime;
if q.odd() {
prod *= prime;
}
}
}
mask <<= 1;
if mask == 0 {
mask = 1;
index += 1;
}
}
assert!(max_prod <= LIMB_MAX_DIV_3);
let l_max_prod = max_prod * 3;
for i in s + 2..=n_to_bit(n / 3) + 1 {
if sieve[index] & mask == 0 {
let prime = Limb::exact_from(id_to_n(i));
if (limb_n / prime).odd() {
if prod > l_max_prod {
factors[j] = prod;
j += 1;
prod = prime;
} else {
prod *= prime;
}
}
}
mask <<= 1;
if mask == 0 {
mask = 1;
index += 1;
}
}
let start = n_to_bit(n >> 1) + 1;
let mut index = bit_to_limb_count_floor(start);
let mut mask = Limb::power_of_2(start & Limb::WIDTH_MASK);
for i in start + 1..=n_to_bit(n) + 1 {
if sieve[index] & mask == 0 {
let prime = Limb::exact_from(id_to_n(i));
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = prime;
} else {
prod *= prime;
}
}
mask <<= 1;
if mask == 0 {
mask = 1;
index += 1;
}
}
if j != 0 {
factors[j] = prod;
j += 1;
match limbs_product(&mut x_and_sieve[..x_len], &mut factors[..j]) {
(size, None) => size,
(size, Some(new_x_and_sieve)) => {
x_and_sieve[..size].copy_from_slice(&new_x_and_sieve[..size]);
size
}
}
} else {
fail_on_untested_path("limbs_2_multiswing_odd, j == 0");
x_and_sieve[0] = prod;
1
}
}
pub(crate) const FAC_DSC_THRESHOLD: usize = 236;
const fn clb2(x: usize) -> usize {
let floor_log_base_2 = (usize::WIDTH as usize - x.leading_zeros() as usize) - 1;
if x.is_power_of_two() {
floor_log_base_2
} else {
floor_log_base_2 + 1
}
}
const FACTORS_PER_LIMB: usize =
(Limb::WIDTH << 1) as usize / (clb2(FAC_DSC_THRESHOLD * FAC_DSC_THRESHOLD - 1) + 1) - 1;
pub(crate) fn log_n_max(n: Limb) -> u64 {
u64::wrapping_from(
NTH_ROOT_NUMB_MASK_TABLE
.iter()
.rposition(|&x| n <= x)
.unwrap(),
) + 1
}
crate_test_fn! {
#[allow(clippy::redundant_comparisons)]
limbs_odd_factorial(n: usize, double: bool) -> Vec<Limb> {
assert!(Limb::convertible_from(n));
if double {
assert!(n > ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1 && n >= FAC_DSC_THRESHOLD);
}
if n <= ODD_FACTORIAL_TABLE_LIMIT {
vec![ONE_LIMB_ODD_FACTORIAL_TABLE[n]]
} else if n <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1 {
let (hi, lo) = Limb::x_mul_y_to_zz(
ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE[(n - 1) >> 1],
ONE_LIMB_ODD_FACTORIAL_TABLE[n >> 1],
);
vec![lo, hi]
} else {
let mut m = n;
let mut s = 0;
while m >= FAC_DSC_THRESHOLD {
m >>= 1;
s += 1;
}
let mut factors = vec![0; m / FACTORS_PER_LIMB + 1];
assert!(m >= FACTORS_PER_LIMB);
assert!(m > ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1);
let mut j = 0;
let mut prod = 1;
let mut max_prod = const { Limb::MAX / (FAC_DSC_THRESHOLD * FAC_DSC_THRESHOLD) as Limb };
assert!(m > ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1);
loop {
factors[j] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
j += 1;
let mut diff = (m - ODD_DOUBLEFACTORIAL_TABLE_LIMIT) & const { 2usize.wrapping_neg() };
if diff & 2 != 0 {
let f = (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + diff) as Limb;
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = f;
} else {
prod *= f;
}
diff -= 2;
}
if diff != 0 {
let mut fac = const { ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 2 }
* (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + diff);
loop {
let f = fac as Limb;
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = f;
} else {
prod *= f;
}
diff -= 4;
fac += diff << 1;
if diff == 0 {
break;
}
}
}
max_prod <<= 2;
m >>= 1;
if m <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT_PLUS_1 {
break;
}
}
factors[j] = prod;
j += 1;
factors[j] = ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE[(m - 1) >> 1];
j += 1;
factors[j] = ONE_LIMB_ODD_FACTORIAL_TABLE[m >> 1];
j += 1;
let mut out = Vec::new();
let (out_size, new_out) = limbs_product(&mut out, &mut factors[..j]);
out = new_out.unwrap();
out.truncate(out_size);
if s != 0 {
let mut size = (n >> Limb::LOG_WIDTH) + 4;
let n_m_1 = u64::exact_from(n - 1);
assert!(limbs_prime_sieve_size::<Limb>(n_m_1) < size - (size >> 1));
let mut swing_and_sieve = vec![0; size];
let sieve_offset = (size >> 1) + 1;
let ss_len = swing_and_sieve.len() - 1;
#[cfg(feature = "32_bit_limbs")]
let count = limbs_prime_sieve_u32(&mut swing_and_sieve[sieve_offset..ss_len], n_m_1);
#[cfg(not(feature = "32_bit_limbs"))]
let count = limbs_prime_sieve_u64(&mut swing_and_sieve[sieve_offset..ss_len], n_m_1);
size = usize::exact_from((count + 1) / log_n_max(Limb::exact_from(n)) + 1);
let mut factors = vec![0; size];
let mut out_len = out.len();
let mut square_scratch: Vec<Limb> = Vec::new();
let mut square: Vec<Limb> = Vec::new();
for i in (0..s).rev() {
let ns = limbs_2_multiswing_odd(
&mut swing_and_sieve,
sieve_offset,
Limb::exact_from(n >> i),
&mut factors,
);
if double && i == 0 {
size = out_len;
if square.len() < size {
square.resize(size, 0);
}
square[..out_len].copy_from_slice(&out[..out_len]);
} else {
size = out_len << 1;
if square.len() < size {
square.resize(size, 0);
}
let scratch_len = limbs_square_to_out_scratch_len(out_len);
if square_scratch.len() < scratch_len {
square_scratch.resize(scratch_len, 0);
}
limbs_square_to_out(
&mut square,
&out[..out_len],
&mut square_scratch[..scratch_len],
);
if square[size - 1] == 0 {
size -= 1;
}
}
out_len = size + ns;
out.resize(out_len, 0);
assert!(ns <= size);
let mut mul_scratch = vec![0; limbs_mul_greater_to_out_scratch_len(size, ns)];
if limbs_mul_greater_to_out(
&mut out,
&square[..size],
&swing_and_sieve[..ns],
&mut mul_scratch,
) == 0
{
out_len -= 1;
}
}
}
if *out.last().unwrap() == 0 {
out.pop();
}
out
}
}}
const FAC_ODD_THRESHOLD: Limb = 24;
#[cfg(feature = "32_bit_limbs")]
const SMALL_FACTORIAL_LIMIT: u64 = 13;
#[cfg(not(feature = "32_bit_limbs"))]
const SMALL_FACTORIAL_LIMIT: u64 = 21;
impl Factorial for Natural {
#[allow(clippy::useless_conversion, clippy::unnecessary_cast)]
fn factorial(n: u64) -> Self {
assert!(Limb::convertible_from(n));
if n < SMALL_FACTORIAL_LIMIT {
Self::from(Limb::factorial(n))
} else if n < const { FAC_ODD_THRESHOLD as u64 } {
let mut factors =
vec![0; usize::wrapping_from(n - SMALL_FACTORIAL_LIMIT) / FACTORS_PER_LIMB + 2];
factors[0] = Limb::factorial(const { SMALL_FACTORIAL_LIMIT - 1 });
let mut j = 1;
let n = Limb::wrapping_from(n);
let mut prod = n;
const MAX_PROD: Limb = Limb::MAX / (FAC_ODD_THRESHOLD | 1);
const LIMB_SMALL_FACTORIAL_LIMIT: Limb = SMALL_FACTORIAL_LIMIT as Limb;
for i in (LIMB_SMALL_FACTORIAL_LIMIT..n).rev() {
if prod > MAX_PROD {
factors[j] = prod;
j += 1;
prod = i;
} else {
prod *= i;
}
}
factors[j] = prod;
j += 1;
let mut xs = Vec::new();
let new_xs = limbs_product(&mut xs, &mut factors[..j]).1;
xs = new_xs.unwrap();
Self::from_owned_limbs_asc(xs)
} else {
let count = if n <= TABLE_LIMIT_2N_MINUS_POPC_2N {
u64::from(TABLE_2N_MINUS_POPC_2N[usize::exact_from((n >> 1) - 1)])
} else {
n - CountOnes::count_ones(n)
};
Self::from_owned_limbs_asc(limbs_odd_factorial(usize::exact_from(n), false)) << count
}
}
}
const FAC_2DSC_THRESHOLD: Limb = ((FAC_DSC_THRESHOLD << 1) | (FAC_DSC_THRESHOLD & 1)) as Limb;
impl DoubleFactorial for Natural {
#[allow(clippy::unnecessary_cast)]
fn double_factorial(n: u64) -> Self {
assert!(Limb::convertible_from(n));
if n.even() {
let half_n = usize::wrapping_from(n >> 1);
let count = if n <= TABLE_LIMIT_2N_MINUS_POPC_2N && n != 0 {
u64::from(TABLE_2N_MINUS_POPC_2N[half_n - 1])
} else {
n - CountOnes::count_ones(n)
};
Self::from_owned_limbs_asc(limbs_odd_factorial(half_n, false)) << count
} else if n <= const { ODD_DOUBLEFACTORIAL_TABLE_LIMIT as u64 } {
Self::from(ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE[usize::wrapping_from(n >> 1)])
} else if n < const { FAC_2DSC_THRESHOLD as u64 } {
let mut factors = vec![0; usize::exact_from(n) / const { FACTORS_PER_LIMB << 1 } + 1];
factors[0] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
let mut j = 1;
let mut n = Limb::wrapping_from(n);
let mut prod = n;
const MAX_PROD: Limb = Limb::MAX / FAC_2DSC_THRESHOLD;
const LIMIT: Limb = ODD_DOUBLEFACTORIAL_TABLE_LIMIT as Limb + 2;
while n > LIMIT {
n -= 2;
if prod > MAX_PROD {
factors[j] = prod;
j += 1;
prod = n;
} else {
prod *= n;
}
}
factors[j] = prod;
j += 1;
let mut xs = Vec::new();
let new_xs = limbs_product(&mut xs, &mut factors[..j]).1;
xs = new_xs.unwrap();
Self::from_owned_limbs_asc(xs)
} else {
Self::from_owned_limbs_asc(limbs_odd_factorial(usize::exact_from(n), true))
}
}
}
impl Multifactorial for Natural {
fn multifactorial(mut n: u64, mut m: u64) -> Self {
assert_ne!(m, 0);
assert!(Limb::convertible_from(n));
assert!(Limb::convertible_from(m));
if n < 3 || n - 3 < m - 1 {
if n == 0 { Self::ONE } else { Self::from(n) }
} else {
let gcd = n.gcd(m);
if gcd > 1 {
n /= gcd;
m /= gcd;
}
if m <= 2 {
if m == 1 {
match gcd {
gcd if gcd > 2 => Self::from(gcd).pow(n) * Self::factorial(n),
2 => Self::double_factorial(n << 1),
_ => Self::factorial(n),
}
} else if gcd > 1 {
Self::from(gcd).pow((n >> 1) + 1) * Self::double_factorial(n)
} else {
Self::double_factorial(n)
}
} else {
let reduced_n = n / m + 1;
let mut n = Limb::exact_from(n);
let m = Limb::exact_from(m);
let mut j = 0;
let mut prod = n;
n -= m;
let max_prod = Limb::MAX / n;
let mut factors = vec![0; usize::exact_from(reduced_n / log_n_max(n) + 2)];
while n > m {
if prod > max_prod {
factors[j] = prod;
j += 1;
prod = n;
} else {
prod *= n;
}
n -= m;
}
factors[j] = n;
j += 1;
factors[j] = prod;
j += 1;
let mut xs = Vec::new();
let new_xs = limbs_product(&mut xs, &mut factors[..j]).1;
xs = new_xs.unwrap();
let x = Self::from_owned_limbs_asc(xs);
if gcd == 1 {
x
} else {
Self::from(gcd).pow(reduced_n) * x
}
}
}
}
}
impl Subfactorial for Natural {
fn subfactorial(n: u64) -> Self {
if n < SUBFACTORIAL_SPLIT_THRESHOLD {
subfactorial_naive(n)
} else if n.odd() {
subfactorial_split_only_b(2, n - 1)
} else {
let mut f = subfactorial_split_only_b(2, n - 2);
f *= Self::from(n);
f += Self::ONE;
f
}
}
}