use malachite_base::num::arithmetic::traits::{FloorSqrt, ModPowerOf2, Parity, Pow, PowerOf2};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{One, Zero};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::num::logic::traits::{BitAccess, LowMask, SignificantBits};
use malachite_nz::natural::Natural;
use malachite_nz::platform::Limb;
fn invert_mod_power_of_2(x: &Natural, pow: u64) -> Natural {
assert!(x.odd());
let mut inverse = Natural::ONE;
for i in 0..pow {
if (&inverse * x).get_bit(i) {
inverse.set_bit(i);
}
}
assert_eq!((&inverse * x).mod_power_of_2(pow), 1);
inverse
}
fn get_log_base_of_2(base: u64, precision: u64) -> Natural {
let extended_precision = precision + 16;
let mut t = Natural::power_of_2(extended_precision);
let two = &t << 1;
let mut log = Natural::ZERO;
let mut base = Natural::from(base) << extended_precision;
for i in (0..precision).rev() {
base = (&base << extended_precision).floor_sqrt();
let next_t = (&t * &base) >> extended_precision;
if next_t < two {
log.set_bit(i);
t = next_t;
}
}
log
}
struct BaseData {
chars_per_limb: u64,
big_base_trailing_zeros: u64,
big_base: Natural,
normalization_steps: u64,
big_base_inverted: Natural,
big_base_inverted_mod_b: Natural,
}
fn generate(base: u64) -> BaseData {
let limit = Natural::power_of_2(Limb::WIDTH);
let mut big_base = Natural::ONE;
let mut chars_per_limb = 0;
while big_base <= limit {
chars_per_limb += 1;
big_base *= Natural::from(base);
}
chars_per_limb -= 1;
big_base = Natural::from(base).pow(chars_per_limb);
let normalization_steps = Limb::WIDTH.wrapping_sub(big_base.significant_bits());
let mut big_base_inverted =
Natural::power_of_2((Limb::WIDTH << 1).wrapping_sub(normalization_steps)) / &big_base;
big_base_inverted.clear_bit(Limb::WIDTH);
let big_base_trailing_zeros = big_base.trailing_zeros().unwrap();
let big_base_odd = &big_base >> big_base_trailing_zeros;
let big_base_inverted_mod_b = invert_mod_power_of_2(&big_base_odd, Limb::WIDTH);
BaseData {
chars_per_limb,
big_base_trailing_zeros,
big_base,
normalization_steps,
big_base_inverted,
big_base_inverted_mod_b,
}
}
fn header() {
let data = generate(10);
println!("// mp_bases[10] data, as literal values");
println!(
"pub const MP_BASES_CHARS_PER_LIMB_10: usize = {};",
data.chars_per_limb
);
println!(
"pub const MP_BASES_BIG_BASE_CTZ_10: usize = {};",
data.big_base_trailing_zeros
);
println!(
"pub const MP_BASES_BIG_BASE_10: Limb = {:#x};",
Limb::exact_from(&data.big_base)
);
println!(
"pub const MP_BASES_BIG_BASE_INVERTED_10: Limb = {:#x};",
Limb::exact_from(&data.big_base_inverted)
);
println!(
"pub const MP_BASES_BIG_BASE_BINVERTED_10: Limb = {:#x};",
Limb::exact_from(&data.big_base_inverted_mod_b)
);
println!(
"pub const MP_BASES_NORMALIZATION_STEPS_10: u64 = {};",
data.normalization_steps
);
}
fn table() {
println!("// Format is (chars_per_limb, logb2, log2b, big_base, big_base_inverted)");
println!("pub const BASES: [(usize, Limb, Limb, Limb, Limb); 257] = [");
println!(" (0, 0, 0, 0, 0), // 0");
println!(" (0, 0, 0, 0, 0), // 1");
for base in 2..=256 {
let mut data = generate(base);
let raw = get_log_base_of_2(base, Limb::WIDTH + 8);
let log_base_of_2 = &raw >> 8;
let log_2_of_base = Natural::low_mask((Limb::WIDTH << 1) + 5) / (raw + Natural::ONE);
if base.is_power_of_two() {
data.big_base = Natural::from(base.significant_bits() - 1);
data.big_base_inverted = Natural::ZERO;
}
println!(
" ({}, {:#x}, {:#x}, {:#x}, {:#x}), // {}",
data.chars_per_limb,
Limb::exact_from(&log_base_of_2),
Limb::exact_from(&log_2_of_base),
Limb::exact_from(&data.big_base),
Limb::exact_from(&data.big_base_inverted),
base
);
}
println!("];");
}
pub(crate) fn generate_string_data() {
println!("// This section is created by digits_data.rs.");
println!();
header();
println!();
table();
}