use std::collections::HashMap;
use std::convert::From;
use crate::prim::{typ::*, mpz::*, mpf::*};
use crate::util;
pub struct SumArctan {
pub ax: Vec<(ui_t, ui_t, ui_t)>
}
impl From<Vec<(si_t, ui_t)>> for SumArctan {
#[inline]
fn from(ax: Vec<(si_t, ui_t)>) -> Self {
let ax = ax.into_iter().map(|(a, x)|
if a < 0 { (1, -a as ui_t, x) } else { (0, a as ui_t, x) } ).collect();
SumArctan{ax}
}
}
impl SumArctan {
pub fn sum_arctan_gregory(&self, m: ui_t) -> mpf_s {
let mut sa = mpf_s::from(0);
let _s = (0..=m).try_fold(&mut sa, |mut sa, n| {
let pre = &mpf_s::from(&*sa);
let k = 2 * n + 1;
let mut sn = mpf_s::from(0);
let _a = self.ax.iter().fold(&mut sn, |mut sn, (sgn, a, x)| {
let s = a / mpf_s::from(&(mpz_s::ui_pow_ui(*x, k) * k));
if 1 == ((n & 1) ^ sgn) { sn -= s; } else { sn += s; }
sn
});
sa += sn;
if sa.cmp(pre) == 0 { None } else { Some(sa) }
});
sa
}
}
pub struct Sigma {
pub digits: mp_size_t
}
impl From<mp_size_t> for Sigma {
#[inline]
fn from(d: mp_size_t) -> Self {
Sigma{digits: d}
}
}
impl Sigma {
pub fn calc_pi_takano(&self) -> mpf_s {
let recursion = self.digits.ilog2().pow(4); let ax = vec![(12, 49), (32, 57), (-5, 239), (12, 110443)];
let pi = SumArctan::from(ax).sum_arctan_gregory(recursion);
pi * 4
}
pub fn calc_pi_machin(&self) -> mpf_s {
let recursion = self.digits.ilog2().pow(4); let ax = vec![(4, 5), (-1, 239)];
let pi = SumArctan::from(ax).sum_arctan_gregory(recursion);
pi * 4
}
pub fn calc_pi_leibniz(&self) -> mpf_s {
let recursion = 10usize.pow(self.digits as u32) as ui_t; let ax = vec![(1, 1)];
let pi = SumArctan::from(ax).sum_arctan_gregory(recursion);
pi * 4
}
pub fn calc_pi_euler(&self) -> mpf_s {
let mut pi = mpf_s::from(1);
let g = &mut mpf_s::from(0);
let d = 10usize.pow(self.digits as u32);
let mut ept = util::EraPrimeTableUI::new(d);
let _p = (0..ept.nprimes()).fold(&mut pi, |pi: mpf_t, k| {
let np = ept.nth_prime(k, 0); let pp = &mpz_s::pow_ui(np, 2);
pi.mul(&mut g.set_z(pp).ui_div(1).ui_sub(1).ui_div(1));
pi
});
pi.mul_ui(6).sqrt()
}
pub fn calc_pi_gauss_legendre(&self) -> mpf_s {
let recursion = self.digits.ilog2(); let a = &mut mpf_s::from(1);
let b = &mut mpf_s::sqrt_ui(2);
let t = &mut mpf_s::from(4);
let p = &mut mpf_s::from(1);
let (a, b, t, _p) = (0..recursion).fold((a, b.ui_div(1), t.ui_div(1), p),
|(a, b, t, p), _k| {
let na = &mut mpf_s::from(&*a); na.add(b).div_ui(2);
let nb = &b.mul(a).sqrt(); t.sub(mpf_s::pow_ui(a.sub(na), 2).mul(p)); (a.set(na), b.set(nb), t, p.mul_ui(2)) });
let mut pi = mpf_s::pow_ui(a.add(b), 2);
pi.div_ui(4).div(t);
pi
}
pub fn calc_napier(&self, x: mpf_r) -> mpf_s {
let significant_digits_of_calc_napier = |n: f64| -> f64 {
let p = (2.0 * std::f64::consts::PI * n).sqrt().log10(); let q = n * (n / std::f64::consts::E).log10(); p + q - 1.0
};
let mut e = mpf_s::from(0);
let g = &mut mpf_s::from(0);
let m = &mut HashMap::<ui_t, mpz_s>::new();
let _s = (0..=self.digits as ui_t).try_fold(&mut e, |e: mpf_t, i| {
let d = if i == 0 { 0 } else { significant_digits_of_calc_napier(i as f64) as mp_size_t };
let n = &mpz_s::fact_cached(i, m);
let f = &mut mpf_s::pow_ui(x, i);
e.add(f.div(g.set_z(n)));
if d >= self.digits { None } else { Some(e) }
}); e
}
}