#![cfg(any(feature = "d153", feature = "wide"))]
use crate::types::widths::wide_trig_d153 as core;
use crate::support::rounding::RoundingMode;
use crate::wide_int::Int512;
const GUARD_NARROW: u32 = 10;
const M: u32 = 128;
#[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, i_idx: usize) -> core::W {
TABLE_CACHE.with(|c| {
{
let cache = c.borrow();
for (cw, tbl) in cache.iter() {
if *cw == w {
return tbl[i_idx];
}
}
}
let tbl = compute_table(w);
let entry = tbl[i_idx];
c.borrow_mut().push((w, tbl));
entry
})
}
#[cfg(not(feature = "std"))]
fn table_entry(w: u32, i_idx: usize) -> core::W {
compute_table(w)[i_idx]
}
fn compute_table(w: u32) -> alloc::vec::Vec<core::W> {
let mut out = alloc::vec::Vec::with_capacity((M + 1) as usize);
let one_w = core::one(w);
out.push(core::zero()); for i in 1..=M {
let scaled = (one_w * core::lit(i as u128)) / core::lit(M as u128);
let f_i = one_w + scaled;
out.push(core::ln_fixed(f_i, w));
}
out
}
#[inline]
#[must_use]
pub(crate) fn ln_strict<const SCALE: u32>(raw: Int512, mode: RoundingMode) -> Int512 {
if raw <= Int512::ZERO {
panic!("D153::ln: argument must be positive");
}
let w = SCALE + GUARD_NARROW;
let v_w = core::to_work_w(raw, GUARD_NARROW);
let one_w = core::one(w);
let pow10_w = one_w;
let two_w = one_w + one_w;
let mut k: i32 = core::bit_length(v_w) as i32 - core::bit_length(one_w) as i32;
let m_w = loop {
let m = if k >= 0 {
v_w >> (k as u32)
} else {
v_w << ((-k) as u32)
};
if m >= two_w {
k += 1;
} else if m < one_w {
k -= 1;
} else {
break m;
}
};
if m_w == one_w {
let r = if k >= 0 {
core::ln2(w) * core::lit(k as u128)
} else if k < 0 {
-(core::ln2(w) * core::lit((-k) as u128))
} else {
core::zero()
};
return core::round_to_storage_with(r, w, SCALE, mode);
}
let i_raw = ((m_w - one_w) * core::lit(M as u128)) / one_w;
let i_i128 = crate::wide_int::wide_cast::<core::W, i128>(i_raw);
let i_idx = if i_i128 >= M as i128 { (M - 1) as usize } else { i_i128 as usize };
let f_i = one_w + (one_w * core::lit(i_idx as u128)) / core::lit(M as u128);
let t = core::div_cached(m_w - f_i, m_w + f_i, pow10_w);
let t2 = core::mul_cached(t, t, pow10_w);
let mut sum = t;
let mut term = t;
let mut j: u128 = 1;
loop {
term = core::mul_cached(term, t2, pow10_w);
let contrib = term / core::lit(2 * j + 1);
if contrib == core::zero() {
break;
}
sum = sum + contrib;
j += 1;
if j > 200 {
break;
}
}
let ln_m = sum + sum + table_entry(w, i_idx);
let k_ln2 = if k >= 0 {
core::ln2(w) * core::lit(k as u128)
} else {
-(core::ln2(w) * core::lit((-k) as u128))
};
let r = k_ln2 + ln_m;
core::round_to_storage_with(r, w, SCALE, mode)
}