use super::definition::Float;
use crate::{_FloatInternals, is};
macro_rules! impl_float_shared_minimax {
() => {
impl_float_shared_minimax![(f32:u32, u32), (f64:u64, u32)];
};
($( ($f:ty:$uf:ty, $ue:ty)),+ $(,)?) => {
$( impl_float_shared_minimax![@$f:$uf, $ue]; )+
};
(@$f:ty:$uf:ty, $ue:ty) => {
impl Float<$f> {
#[doc = crate::_FLOAT_FORMULA_SIN_MINIMAX!()]
pub const fn sin_minimax(self) -> Float<$f> {
let (x, _flip) = self.reduce_half_pi();
x.sin_minimax_from_reduced()
}
#[doc = crate::_FLOAT_FORMULA_COS_MINIMAX!()]
pub const fn cos_minimax(self) -> Float<$f> {
let (x, flip) = self.reduce_half_pi();
x.cos_minimax_from_reduced(flip)
}
#[inline(always)]
pub const fn sin_cos_minimax(self) -> (Float<$f>, Float<$f>) {
let (x, flip) = self.reduce_half_pi();
(x.sin_minimax_from_reduced(), x.cos_minimax_from_reduced(flip))
}
#[inline(always)]
const fn sin_minimax_from_reduced(self) -> Float<$f> {
let x2 = self.0 * self.0;
let poly = Float(x2).eval_poly_const::<{_FloatInternals::<$f>::SIN_COS_DEGREE}>(
&_FloatInternals::<$f>::SIN_COEFFS
).0;
Float(self.0 + self.0 * x2 * poly)
}
#[inline(always)]
const fn cos_minimax_from_reduced(self, flip: bool) -> Float<$f> {
let x2 = self.0 * self.0;
let poly = Float(x2).eval_poly_const::<{_FloatInternals::<$f>::SIN_COS_DEGREE}>(
&_FloatInternals::<$f>::COS_COEFFS
).0;
let c = 1.0 + x2 * poly;
Float(is![flip, -c, c])
}
#[inline(always)]
const fn reduce_half_pi(self) -> (Float<$f>, bool) {
use crate::FloatConst;
let mut xr = self.0 - <$f>::TAU * Float(self.0 / <$f>::TAU).round().0;
let mut flip = false;
if xr > <$f>::FRAC_PI_2 {
xr = <$f>::PI - xr;
flip = true;
} else if xr < - <$f>::FRAC_PI_2 {
xr = - <$f>::PI - xr;
flip = true;
}
(Float(xr), flip)
}
}
};
}
impl_float_shared_minimax!();