use core::fmt::{Display, Formatter};
use dashu::{base::SquareRoot, float::DBig, integer::IBig};
use std::ops::{Add, Div, Mul};
#[derive(Copy, Clone, Debug)]
pub struct RamanujanL1 {
a: i64,
b: i64,
c: i64,
d: i64,
e: i64,
f: i64,
}
impl Display for RamanujanL1 {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(
f,
"({}Sqrt[{}])/({}-Sum[Product[(72j^3-108j^2+46j-5)/({}j^3),{{j,1,k}}]/({}k+{}),{{k,1,Infinity}}])",
self.a, self.b, self.c, self.d, self.e, self.f,
)
}
}
impl RamanujanL1 {
pub const J7: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
pub const J11: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
pub const J19: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
pub const J43: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
pub const J67: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
pub const J163: Self = Self { a: 426880, b: 10005, c: 13591409, d: 10939058860032000, e: 545140134, f: 13591409 };
}
impl RamanujanL1 {
fn binary_split(&self, j: i64, i: i64) -> (IBig, IBig, IBig) {
if i == j + 1 {
let pab = IBig::from(-(6 * j - 5) * (2 * j - 1) * (6 * j - 1));
let qab = IBig::from(j).pow(3).mul(self.d);
let rab = IBig::from(self.e * j + self.f).mul(&pab);
(pab, qab, rab)
}
else {
let m = (j + i) / 2;
let (pam, qam, ram) = self.binary_split(j, m);
let (pmb, qmb, rmb) = self.binary_split(m, i);
let pab = pmb.mul(&pam);
let qab = qam.mul(&qmb);
let rab = ram.mul(qmb) + pam * rmb;
(pab, qab, rab)
}
}
pub fn run(&self, iterators: usize) -> DBig {
const RELAXATION: usize = 15;
let (_, q1n, r1n) = self.binary_split(1, iterators as i64);
let d = DBig::from(self.c).mul(&q1n).add(r1n).with_precision(RELAXATION * iterators).value();
let n = DBig::from(q1n.mul(self.a)).with_precision(RELAXATION * iterators).value();
let sqrt = DBig::from(self.b).with_precision(RELAXATION * iterators).value().sqrt();
n.mul(sqrt).div(d)
}
}
pub fn chudnovsky(iterators: usize) -> DBig {
RamanujanL1::J163.run(iterators)
}