use crate::algos::exp::exp_generic as eg;
use crate::int::types::compute_limbs::ComputeLimbs;
use crate::int::types::traits::BigInt;
fn sin_taylor<S: BigInt>(r: S, w: u32) -> S
where
S::Scratch: ComputeLimbs,
{
let r2 = eg::mul::<S>(r, r, w);
let mut sum = r;
let mut term = r;
let mut k: u128 = 1;
loop {
term = eg::mul::<S>(term, r2, w) / eg::lit::<S>(((2 * k) * (2 * k + 1)) as i128);
if term == eg::zero::<S>() {
break;
}
if k % 2 == 1 {
sum = sum - term;
} else {
sum = sum + term;
}
k += 1;
if k > eg::SERIES_CAP {
break;
}
}
sum
}
fn cos_taylor<S: BigInt>(r: S, w: u32) -> S
where
S::Scratch: ComputeLimbs,
{
let r2 = eg::mul::<S>(r, r, w);
let one_w = eg::one::<S>(w);
let mut sum = one_w;
let mut term = one_w;
let mut k: u128 = 1;
loop {
term = eg::mul::<S>(term, r2, w) / eg::lit::<S>(((2 * k - 1) * (2 * k)) as i128);
if term == eg::zero::<S>() {
break;
}
if k % 2 == 1 {
sum = sum - term;
} else {
sum = sum + term;
}
k += 1;
if k > eg::SERIES_CAP {
break;
}
}
sum
}
pub(crate) fn sin_fixed<S: BigInt>(v_w: S, w: u32, pi_w: S) -> S
where
S::Scratch: ComputeLimbs,
{
let tau = pi_w + pi_w;
let hp = pi_w >> 1;
let qp = hp >> 1; let q = eg::round_to_nearest_int::<S>(eg::div::<S>(v_w, tau, w), w);
let r = v_w - eg::scale_by_k::<S>(tau, q);
let neg = r < eg::zero::<S>();
let abs_r = if neg { -r } else { r };
let reduced = if abs_r >= hp { pi_w - abs_r } else { abs_r };
let s = if reduced > qp {
cos_taylor::<S>(hp - reduced, w)
} else {
sin_taylor::<S>(reduced, w)
};
if neg { -s } else { s }
}
pub(crate) fn cos_fixed<S: BigInt>(v_w: S, w: u32, pi_w: S) -> S
where
S::Scratch: ComputeLimbs,
{
sin_fixed::<S>((pi_w >> 1) - v_w, w, pi_w)
}
fn atan_taylor<S: BigInt>(x: S, w: u32) -> S
where
S::Scratch: ComputeLimbs,
{
let x2 = eg::mul::<S>(x, x, w);
let mut sum = x;
let mut term = x;
let mut k: u128 = 1;
loop {
term = eg::mul::<S>(term, x2, w);
let contrib = term / eg::lit::<S>((2 * k + 1) as i128);
if contrib == eg::zero::<S>() {
break;
}
if k % 2 == 1 {
sum = sum - contrib;
} else {
sum = sum + contrib;
}
k += 1;
if k > eg::SERIES_CAP {
break;
}
}
sum
}
pub(crate) fn atan_fixed<S: BigInt>(v_w: S, w: u32, pi_w: S) -> S
where
S::Scratch: ComputeLimbs,
{
let one_w = eg::one::<S>(w);
let sign = v_w < eg::zero::<S>();
let mut x = if sign { -v_w } else { v_w };
let mut add_half_pi = false;
if x > one_w {
x = eg::div::<S>(one_w, x, w);
add_half_pi = true;
}
let halvings: u32 = if w < 60 {
5
} else if w < 110 {
6
} else {
7
};
let pow10_w = one_w;
for _ in 0..halvings {
let x2 = eg::mul::<S>(x, x, w);
let denom = one_w + eg::sqrt_fixed::<S>(one_w + x2, w);
x = eg::div_cached::<S>(x, denom, pow10_w);
}
let mut result = atan_taylor::<S>(x, w) << halvings;
if add_half_pi {
result = (pi_w >> 1) - result;
}
if sign { -result } else { result }
}
pub(crate) fn sin_cos_fixed<S: BigInt>(v_w: S, w: u32, pi_w: S) -> (S, S)
where
S::Scratch: ComputeLimbs,
{
let tau = pi_w + pi_w;
let hp = pi_w >> 1;
let qp = hp >> 1;
let q = eg::round_to_nearest_int::<S>(eg::div::<S>(v_w, tau, w), w);
let r = v_w - eg::scale_by_k::<S>(tau, q);
let sin_neg = r < eg::zero::<S>();
let abs_r = if sin_neg { -r } else { r };
let cos_neg = abs_r > hp; let reduced = if cos_neg { pi_w - abs_r } else { abs_r };
let s_abs = if reduced > qp {
cos_taylor::<S>(hp - reduced, w)
} else {
sin_taylor::<S>(reduced, w)
};
let one_w = eg::one::<S>(w);
let s2 = eg::mul::<S>(s_abs, s_abs, w);
let cos_abs = eg::sqrt_fixed::<S>(one_w - s2, w);
let sin_result = if sin_neg { -s_abs } else { s_abs };
let cos_result = if cos_neg { -cos_abs } else { cos_abs };
(sin_result, cos_result)
}