#![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 GUARD_NARROW: u32 = 10;
fn asin_fixed(v: core::W, w: u32) -> core::W {
let one_w = core::one(w);
let abs_v = if v < core::zero() { -v } else { v };
if abs_v > one_w {
panic!("D57::asin: argument out of domain [-1, 1]");
}
let half_w = one_w / core::lit(2);
if abs_v == one_w {
let hp = core::half_pi(w);
return if v < core::zero() { -hp } else { hp };
}
if abs_v <= half_w {
let denom = core::sqrt_fixed(one_w - core::mul(v, v, w), w);
return core::atan_fixed(core::div(v, denom, w), w);
}
let inner = (one_w - abs_v) / core::lit(2);
let inner_sqrt = core::sqrt_fixed(inner, w);
let inner_denom = core::sqrt_fixed(
one_w - core::mul(inner_sqrt, inner_sqrt, w),
w,
);
let inner_asin = core::atan_fixed(core::div(inner_sqrt, inner_denom, w), w);
let result_abs = core::half_pi(w) - inner_asin - inner_asin;
if v < core::zero() { -result_abs } else { result_abs }
}
#[inline]
#[must_use]
pub(crate) fn asin_strict<const SCALE: u32>(raw: Int192, mode: RoundingMode) -> Int192 {
let w = SCALE + GUARD_NARROW;
let v = core::to_work_w(raw, GUARD_NARROW);
let r = asin_fixed(v, w);
core::round_to_storage_with(r, w, SCALE, mode)
}
#[inline]
#[must_use]
pub(crate) fn acos_strict<const SCALE: u32>(raw: Int192, mode: RoundingMode) -> Int192 {
let w = SCALE + GUARD_NARROW;
let v = core::to_work_w(raw, GUARD_NARROW);
let asin_w = asin_fixed(v, w);
let r = core::half_pi(w) - asin_w;
core::round_to_storage_with(r, w, SCALE, mode)
}
#[inline]
#[must_use]
pub(crate) fn atan2_strict<const SCALE: u32>(
y_raw: Int192,
x_raw: Int192,
mode: RoundingMode,
) -> Int192 {
let w = SCALE + GUARD_NARROW;
let zero_s = Int192::ZERO;
let r = if x_raw == zero_s {
if y_raw > zero_s {
core::half_pi(w)
} else if y_raw < zero_s {
-core::half_pi(w)
} else {
core::zero()
}
} else {
let y = core::to_work_w(y_raw, GUARD_NARROW);
let x = core::to_work_w(x_raw, GUARD_NARROW);
let zero_w = core::zero();
let abs_y = if y < zero_w { -y } else { y };
let abs_x = if x < zero_w { -x } else { x };
let base = if abs_x >= abs_y {
core::atan_fixed(core::div(y, x, w), w)
} else {
let inv = core::atan_fixed(core::div(x, y, w), w);
let hp = core::half_pi(w);
let same_sign = (y < zero_w) == (x < zero_w);
if same_sign { hp - inv } else { -hp - inv }
};
if x_raw > zero_s {
base
} else if y_raw >= zero_s {
base + core::pi(w)
} else {
base - core::pi(w)
}
};
core::round_to_storage_with(r, w, SCALE, mode)
}