#![cfg(any(feature = "d57", feature = "wide"))]
use crate::types::widths::wide_trig_d57 as core;
use crate::support::rounding::RoundingMode;
use crate::wide_int::Int192;
const M: u32 = 512;
#[cfg(feature = "std")]
::std::thread_local! {
static TABLE_CACHE: ::core::cell::RefCell<alloc::vec::Vec<(u32, alloc::vec::Vec<core::W>)>> =
const { ::core::cell::RefCell::new(alloc::vec::Vec::new()) };
}
#[cfg(feature = "std")]
fn table_entry(w: u32, j_idx: usize) -> core::W {
TABLE_CACHE.with(|c| {
{
let cache = c.borrow();
for (cw, tbl) in cache.iter() {
if *cw == w {
return tbl[j_idx];
}
}
}
let tbl = compute_table(w);
let entry = tbl[j_idx];
c.borrow_mut().push((w, tbl));
entry
})
}
#[cfg(not(feature = "std"))]
fn table_entry(w: u32, j_idx: usize) -> core::W {
compute_table(w)[j_idx]
}
fn compute_table(w: u32) -> alloc::vec::Vec<core::W> {
let mut out = alloc::vec::Vec::with_capacity(M as usize);
let one_w = core::one(w);
out.push(core::zero());
for j in 1..M {
let cj_w = (one_w * core::lit(j as u128)) / core::lit(M as u128);
out.push(core::atan_fixed(cj_w, w));
}
out
}
#[inline]
#[must_use]
pub(crate) fn atan_strict<const SCALE: u32>(raw: Int192, mode: RoundingMode) -> Int192 {
if raw == Int192::ZERO {
return Int192::ZERO;
}
let w = SCALE + core::GUARD;
let v_w = core::to_work(raw);
let one_w = core::one(w);
let pow10_w = one_w;
let sign_neg = v_w < core::zero();
let mut x = if sign_neg { -v_w } else { v_w };
let add_half_pi = x > one_w;
if add_half_pi {
x = core::div_cached(one_w, x, pow10_w);
}
let x_times_m = x * core::lit(M as u128);
let j_signed = core::round_to_nearest_int(x_times_m, w);
let j_idx: u32 = if j_signed >= M as i128 {
M - 1
} else if j_signed < 0 {
0
} else {
j_signed as u32
};
let cj_w = if j_idx == 0 {
core::zero()
} else {
(one_w * core::lit(j_idx as u128)) / core::lit(M as u128)
};
let y = if j_idx == 0 {
x
} else {
let numer = x - cj_w;
let denom = one_w + core::mul_cached(cj_w, x, pow10_w);
core::div_cached(numer, denom, pow10_w)
};
let atan_y = {
let y2 = core::mul_cached(y, y, pow10_w);
let mut sum = y;
let mut term = y;
let mut k: u128 = 1;
loop {
term = core::mul_cached(term, y2, pow10_w);
let contrib = term / core::lit(2 * k + 1);
if contrib == core::zero() {
break;
}
if k % 2 == 1 {
sum = sum - contrib;
} else {
sum = sum + contrib;
}
k += 1;
if k > 200 {
break;
}
}
sum
};
let atan_abs_x = table_entry(w, j_idx as usize) + atan_y;
let mut result = if add_half_pi {
core::half_pi(w) - atan_abs_x
} else {
atan_abs_x
};
if sign_neg {
result = -result;
}
core::round_to_storage_with(result, w, SCALE, mode)
}