use crate::algos::support::wide_trig_core::WideTrigCore;
use crate::support::rounding::RoundingMode;
#[derive(Copy, Clone)]
pub(crate) enum Which {
Sin,
Cos,
}
#[inline]
#[must_use]
fn sin_cos_strict<C: WideTrigCore, const SCALE: u32, const M: u32>(
raw: C::Storage,
mode: RoundingMode,
which: Which,
) -> C::Storage
where
<C::W as crate::int::types::traits::BigInt>::Scratch:
crate::int::types::compute_limbs::ComputeLimbs,
{
if raw == C::storage_zero() {
return match which {
Which::Sin => C::storage_zero(),
Which::Cos => C::storage_one(SCALE),
};
}
let w = SCALE + C::GUARD;
let v_w = C::to_work(raw);
let one_w = C::one(w);
let pow10_w = one_w;
let pi_w = C::pi::<SCALE>(w);
let half_pi_w = C::half_pi::<SCALE>(w);
let k = C::round_to_nearest_int(C::div_cached(v_w, half_pi_w, pow10_w), w);
let k_half_pi = if k >= 0 {
half_pi_w * C::lit(k as u128)
} else {
-(half_pi_w * C::lit((-k) as u128))
};
let r = v_w - k_half_pi;
let four_m = C::lit((4 * M) as u128);
let j_signed = C::round_to_nearest_int(C::div_cached(r * four_m, pi_w, pow10_w), w);
let cj_signed_w = if j_signed >= 0 {
(pi_w * C::lit(j_signed as u128)) / four_m
} else {
-((pi_w * C::lit((-j_signed) as u128)) / four_m)
};
let delta = r - cj_signed_w;
let j_abs = j_signed.unsigned_abs() as u32;
debug_assert!(j_abs <= M, "sin_cos_strict tang: table index {j_abs} > M={M}");
let j_idx = if j_abs > M { M as usize } else { j_abs as usize };
let (sin_cj_abs, cos_cj) = C::sincos_table_entry::<SCALE>(w, j_idx, M);
let sin_cj = if j_signed < 0 { -sin_cj_abs } else { sin_cj_abs };
let delta2 = C::mul(delta, delta, w);
let sin_delta = {
let mut sum = delta;
let mut term = delta;
let mut k_term: u128 = 1;
loop {
term = C::mul(term, delta2, w) / C::lit((2 * k_term) * (2 * k_term + 1));
if term == C::zero() {
break;
}
if k_term % 2 == 1 {
sum = sum - term;
} else {
sum = sum + term;
}
k_term += 1;
if k_term > 200 {
break;
}
}
sum
};
let cos_delta = {
let mut sum = one_w;
let mut term = one_w;
let mut k_term: u128 = 1;
loop {
term = C::mul(term, delta2, w) / C::lit((2 * k_term - 1) * (2 * k_term));
if term == C::zero() {
break;
}
if k_term % 2 == 1 {
sum = sum - term;
} else {
sum = sum + term;
}
k_term += 1;
if k_term > 200 {
break;
}
}
sum
};
let sin_r = C::mul(sin_cj, cos_delta, w) + C::mul(cos_cj, sin_delta, w);
let cos_r = C::mul(cos_cj, cos_delta, w) - C::mul(sin_cj, sin_delta, w);
let quadrant = ((k % 4) + 4) % 4;
let (sin_x, cos_x) = match quadrant {
0 => (sin_r, cos_r),
1 => (cos_r, -sin_r),
2 => (-sin_r, -cos_r),
3 => (-cos_r, sin_r),
_ => unreachable!(),
};
let result = match which {
Which::Sin => sin_x,
Which::Cos => cos_x,
};
match crate::algos::support::wide_trig_core::round_to_storage_clear_of_tie_g::<C::Storage, C::W>(
result, w, SCALE, mode, C::storage_max(), C::storage_min(),
) {
Some(st) => st,
None => match which {
Which::Sin => crate::algos::support::wide_trig_core::sin_series::<C, SCALE>(raw, mode),
Which::Cos => crate::algos::support::wide_trig_core::cos_series::<C, SCALE>(raw, mode),
},
}
}
#[inline]
#[must_use]
pub(crate) fn sin_tang_with_taylor<C: WideTrigCore, const SCALE: u32, const M: u32>(
raw: C::Storage,
mode: RoundingMode,
) -> C::Storage
where
<C::W as crate::int::types::traits::BigInt>::Scratch:
crate::int::types::compute_limbs::ComputeLimbs,
{
sin_cos_strict::<C, SCALE, M>(raw, mode, Which::Sin)
}
#[inline]
#[must_use]
pub(crate) fn cos_tang_with_taylor<C: WideTrigCore, const SCALE: u32, const M: u32>(
raw: C::Storage,
mode: RoundingMode,
) -> C::Storage
where
<C::W as crate::int::types::traits::BigInt>::Scratch:
crate::int::types::compute_limbs::ComputeLimbs,
{
sin_cos_strict::<C, SCALE, M>(raw, mode, Which::Cos)
}