use dashu::integer::IBig;
use dashu_float::round::mode::Zero;
use dashu_float::{Context, FBig};
use dashu_macros::{dbig, ibig};
pub fn binary_split(a: usize, b: usize) -> (IBig, IBig, IBig) {
if b - a == 1 {
let pab =
-(ibig!(6) * a - ibig!(5)) * (ibig!(2) * a - ibig!(1)) * (ibig!(6) * a - ibig!(1));
let qab = ibig!(10939058860032000) * a.pow(3);
let rab = &pab * (ibig!(545140134) * a + ibig!(13591409));
(pab, qab, rab)
} else {
let m = (a + b) / 2;
let ((pam, qam, ram), (pmb, qmb, rmb)) = rayon::join(
|| binary_split(a, m), || binary_split(m, b), );
let pab = &pam * &pmb;
let qab = &qam * &qmb;
let rab = &qmb * &ram + &pam * &rmb;
(pab, qab, rab)
}
}
pub fn chudnovsky(iterations: usize, digits: usize) -> FBig<Zero, 10> {
let iterations = iterations.max(2);
let precision = digits + 2;
let context = Context::<Zero>::new(precision);
let (q, (_p1n, q1n, r1n)) = rayon::join(
|| context.sqrt(dbig!(10005).repr()).value(),
|| binary_split(1, iterations),
);
let (n, d) = rayon::join(
|| ibig!(426880) * &q * &q1n,
|| ibig!(13591409) * &q1n + &r1n,
);
n / d
}
pub fn chudnovsky_iterations(digits: usize) -> usize {
const DIGITS_PER_TERM: f64 = 14.181647462;
((digits as f64) / DIGITS_PER_TERM).ceil() as usize
}
pub fn compute_pi(digits: usize) -> String {
let iterations = chudnovsky_iterations(digits);
let pi = chudnovsky(iterations, digits);
let pi_str = pi.to_string();
pi_str.chars().take(digits + 2).collect()
}