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 GUARD: u32>(
raw: C::Storage,
mode: RoundingMode,
which: Which,
) -> C::Storage {
if raw == C::storage_zero() {
return match which {
Which::Sin => C::storage_zero(),
Which::Cos => C::storage_one(SCALE),
};
}
let r = C::round_to_storage_directed(GUARD, SCALE, mode, &mut |guard| {
let v_w = C::to_work_scaled(raw, guard);
match which {
Which::Sin => C::sin_fixed::<SCALE>(v_w, SCALE + guard),
Which::Cos => C::cos_fixed::<SCALE>(v_w, SCALE + guard),
}
});
crate::algos::support::wide_trig_core::adjust_bounded_extremum::<C, SCALE>(r, raw, mode)
}
#[inline]
#[must_use]
pub(crate) fn sin_narrow_with_taylor<C: WideTrigCore, const SCALE: u32, const GUARD: u32>(
raw: C::Storage,
mode: RoundingMode,
) -> C::Storage {
sin_cos_strict::<C, SCALE, GUARD>(raw, mode, Which::Sin)
}
#[inline]
#[must_use]
pub(crate) fn cos_narrow_with_taylor<C: WideTrigCore, const SCALE: u32, const GUARD: u32>(
raw: C::Storage,
mode: RoundingMode,
) -> C::Storage {
sin_cos_strict::<C, SCALE, GUARD>(raw, mode, Which::Cos)
}
#[inline]
#[must_use]
pub(crate) fn tan_narrow_with_taylor<
C: WideTrigCore,
const SCALE: u32,
const GUARD: u32,
const NEAR_POLE: bool,
>(
raw: C::Storage,
mode: RoundingMode,
) -> C::Storage
where
<C::W as crate::int::types::traits::BigInt>::Scratch:
crate::int::types::compute_limbs::ComputeLimbs,
{
if raw == C::storage_zero() {
return C::storage_zero();
}
let w0 = SCALE + GUARD;
let v0 = C::to_work_scaled(raw, GUARD);
let (sin0, cos0) = C::sin_cos_fixed::<SCALE>(v0, w0);
if cos0 == C::zero() {
panic!("wide-tier tan: cosine is zero (argument is an odd multiple of pi/2)");
}
let tie_walker = |base_guard: u32| -> C::Storage {
C::round_to_storage_directed(base_guard, SCALE, mode, &mut |guard| {
let w = SCALE + guard;
let (s, c) = C::sin_cos_fixed::<SCALE>(C::to_work_scaled(raw, guard), w);
if c == C::zero() {
panic!("wide-tier tan: cosine is zero (argument is an odd multiple of pi/2)");
}
C::div(s, c, w)
})
};
if !NEAR_POLE {
let r = C::div(sin0, cos0, w0);
if let Some(st) = crate::algos::support::wide_trig_core::round_to_storage_clear_of_tie_g::<
C::Storage,
C::W,
>(r, w0, SCALE, mode, C::storage_max(), C::storage_min())
{
return st;
}
return tie_walker(GUARD);
}
let probe = C::div(sin0, cos0, w0);
let extra = super::near_pole_tan::tan_extra_digits(C::bit_length(probe), w0);
if extra == 0 {
if let Some(st) = crate::algos::support::wide_trig_core::round_to_storage_clear_of_tie_g::<
C::Storage,
C::W,
>(probe, w0, SCALE, mode, C::storage_max(), C::storage_min())
{
return st;
}
return tie_walker(GUARD);
}
let w = w0 + extra;
let v_w = C::to_work_scaled(raw, GUARD + extra);
let (sin_w, cos_w) = C::sin_cos_fixed::<SCALE>(v_w, w);
let r = C::div(sin_w, cos_w, w);
if let Some(st) = crate::algos::support::wide_trig_core::round_to_storage_clear_of_tie_g::<
C::Storage,
C::W,
>(r, w, SCALE, mode, C::storage_max(), C::storage_min())
{
return st;
}
tie_walker(GUARD + extra)
}