use crate::divider::Divider;
use crate::vector::ops::{AddMasked as _, MulMasked as _, SubMasked as _};
use core::f64::consts::{LN_10, LOG2_E, SQRT_2};
use super::*;
impl<V: FloatVectorWithBits<Element = f64>> SpecializedCoreMath<f64> for V {
#[inline(always)]
fn inverse_sqrt<P: Policy>(self) -> Self {
super::generic::inverse_sqrt_internal::<V, f64, P>(self)
}
}
impl<V: FloatVectorWithBits<Element = f64>> SpecializedRealMath<f64> for V {
#[inline(always)]
fn atan2<P: Policy>(self, x: Self) -> Self {
atan_internal::<Self, P, true>(self, x)
}
#[inline(always)]
fn wrap_angle<P: Policy>(self) -> Self {
let x = self;
let n = ((x + Self::PI) * (Self::FRAC_1_PI * Self::HALF)).floor();
if const { Self::HAS_TRUE_FMA || P::POLICY.precision.le(PrecisionPolicy::Average) } {
return n.nmul_adde(Self::TAU, x);
}
let tau_hi: V = crate::const_splat!(f64: hexf::hexf64!("0x1.921fb54442d18p+2"));
let tau_lo: V = crate::const_splat!(f64: hexf::hexf64!("0x1.1a62633145c07p-52"));
(x - n * tau_hi) - n * tau_lo
}
}
#[rustfmt::skip]
impl<V: FloatVectorWithBits<Element = f64>> SpecializedSpatialMath<f64> for V {
#[inline(always)] fn l2_norm_squared<P: Policy>(self) -> Self { self * self }
#[inline(always)] fn l2_norm<P: Policy>(self) -> Self { self.abs() }
#[inline(always)] fn l1_norm<P: Policy>(self) -> Self { self.abs() }
}
impl<V: FloatVectorWithBits<Element = f64>> SpecializedTranscendentalMath<f64> for V {
#[inline(always)]
fn sinc<P: Policy>(self) -> Self {
super::generic::sinc_internal::<V, f64, P>(self)
}
#[inline(always)]
fn sinc_pi<P: Policy>(self) -> Self {
super::generic::sinc_pi_internal::<V, f64, P>(self)
}
#[inline(always)]
fn log_n<P: Policy, const N: usize>(self) -> Self {
super::generic::log_n_internal::<V, f64, P, N>(self)
}
#[inline(always)]
fn sin_cos<P: Policy>(self) -> (Self, Self) {
sincos_d_internal::<P, V, false>(self)
}
#[inline(always)]
fn sincos_pi<P: Policy>(self) -> (Self, Self) {
sincos_d_internal::<P, V, true>(self)
}
#[inline(always)]
fn sinh_cosh<P: Policy>(self) -> (Self, Self) {
let x0 = self;
let x = x0.abs().flush_denormals::<P>();
let y = x.exph_p::<P>();
let qy = V::FRAC_1_4 / y;
let mut sinh = y - qy;
let cosh = y + qy;
let x_small = x.cmp_le(V::ONE);
if const { P::POLICY.avoid_branching } || x_small.any() {
let x2 = x * x;
#[rustfmt::skip]
let y1 = x2.poly_rational_p::<P, _, _>(
&[
-3.51754964808151394800E5,
-1.15614435765005216044E4,
-1.63725857525983828727E2,
-7.89474443963537015605E-1,
],
&[
-2.11052978884890840399E6,
3.61578279834431989373E4,
-2.77711081420602794433E2,
1.0,
],
).mul_adde(x * x2, x);
sinh = x_small.select(y1, sinh);
}
(sinh.mul_sign(x0), cosh)
}
#[inline(always)]
fn sinh<P: Policy>(self) -> Self {
let x0 = self;
let x = x0.abs().flush_denormals::<P>();
let x_small = x.cmp_le(V::ONE);
let mut y2 = V::EMPTY;
if const { P::POLICY.avoid_branching } || !x_small.all() {
y2 = x.exph_p::<P>();
y2 -= V::FRAC_1_4 / y2;
if const { P::POLICY.avoid_precision_branches() } {
return y2.mul_sign(x0);
}
}
if const { P::POLICY.avoid_branching } || x_small.any() {
let x2 = x * x;
#[rustfmt::skip]
let y1 = x2.poly_rational_p::<P, _, _>(
&[
-3.51754964808151394800E5,
-1.15614435765005216044E4,
-1.63725857525983828727E2,
-7.89474443963537015605E-1,
],
&[
-2.11052978884890840399E6,
3.61578279834431989373E4,
-2.77711081420602794433E2,
1.0,
],
).mul_adde(x * x2, x);
y2 = x_small.select(y1, y2);
}
y2.mul_sign(x0)
}
#[inline(always)]
fn cosh<P: Policy>(self) -> Self {
let y = self.abs().exph_p::<P>();
y + V::FRAC_1_4 / y
}
#[inline(always)]
fn tanh<P: Policy>(self) -> Self {
let x0 = self;
let x = x0.abs().flush_denormals::<P>();
let x_small = x.cmp_le(crate::const_splat!(f64: 0.625));
let mut y2 = V::EMPTY;
if const { P::POLICY.avoid_branching } || !x_small.all() {
let h = (x + x).exph_p::<P>();
y2 = (h - V::HALF) / (h + V::HALF);
if const { P::POLICY.check_overflow } {
y2 = x.cmp_gt(crate::const_splat!(f64: 350.0)).select(V::ONE, y2);
}
if const { P::POLICY.avoid_precision_branches() } {
return y2.mul_sign(x0);
}
}
if const { P::POLICY.avoid_branching } || x_small.any() {
let x2 = x * x;
#[rustfmt::skip]
let y1 = x2.poly_rational_p::<P, _, _>(
&[
-1.61468768441708447952E3,
-9.92877231001918586564E1,
-9.64399179425052238628E-1,
],
&[
4.84406305325125486048E3,
2.23548839060100448583E3,
1.12811678491632931402E2,
1.0,
],
).mul_adde(x * x2, x);
y2 = x_small.select(y1, y2);
}
y2.mul_sign(x0)
}
#[inline(always)]
fn asin<P: Policy>(self) -> Self {
asin_internal::<Self, P, false>(self)
}
#[inline(always)]
fn acos<P: Policy>(self) -> Self {
asin_internal::<Self, P, true>(self)
}
#[inline(always)]
fn atan<P: Policy>(self) -> Self {
atan_internal::<Self, P, false>(self, V::ZERO)
}
#[inline(always)]
fn asinh<P: Policy>(self) -> Self {
let x0 = self;
let x = x0.abs().flush_denormals::<P>();
let x2 = x * x;
let x_small = x.cmp_le(crate::const_splat!(f64: 0.533));
let mut y2 = V::EMPTY;
if const { P::POLICY.avoid_branching } || !x_small.all() {
y2 = ((x2 + V::ONE).sqrt() + x).ln_p::<P>();
if const { P::POLICY.check_overflow || !P::POLICY.avoid_precision_branches() } {
let x_huge = x.cmp_gt(crate::const_splat!(f64: 1e20));
if crate::unlikely(x_huge.any()) {
y2 = x_huge.select(x.ln_p::<P>() + V::LN_2, y2);
}
}
}
if const { P::POLICY.avoid_branching } || x_small.any() {
let y1 = x2
.poly_rational_p::<P, _, _>(
&[
-5.56682227230859640450E0,
-9.09030533308377316566E0,
-4.37390226194356683570E0,
-5.91750212056387121207E-1,
-4.33231683752342103572E-3,
],
&[
3.34009336338516356383E1,
6.95722521337257608734E1,
4.86042483805291788324E1,
1.28757002067426453537E1,
1.0,
],
)
.mul_adde(x * x2, x);
y2 = x_small.select(y1, y2);
}
y2.mul_sign(x0)
}
#[inline(always)]
fn acosh<P: Policy>(self) -> Self {
let x0 = self.flush_denormals::<P>();
let x1 = x0 - V::ONE;
let x_small = x1.cmp_le(crate::const_splat!(f64: 0.49));
let mut y2 = V::EMPTY;
if const { P::POLICY.avoid_branching } || !x_small.all() {
y2 = (x0.mul_sube(x0, V::ONE).sqrt() + x0).ln_p::<P>();
if const { P::POLICY.check_overflow && !P::POLICY.avoid_precision_branches() } {
let x_huge = x1.cmp_gt(crate::const_splat!(f64: 1e20));
if crate::unlikely(x_huge.any()) {
y2 = x_huge.select(x0.ln_p::<P>() + V::LN_2, y2);
}
}
if const { P::POLICY.avoid_precision_branches() } {
if const { P::POLICY.check_overflow } {
y2 = x0.cmp_lt(V::ONE).select(V::NAN, y2);
}
return y2;
}
}
if const { P::POLICY.avoid_branching } || x_small.any() {
let mut y1 = x1.sqrt()
* x1.poly_rational_p::<P, _, _>(
&[
1.10855947270161294369E5,
1.08102874834699867335E5,
3.43989375926195455866E4,
3.94726656571334401102E3,
1.18801130533544501356E2,
],
&[
7.83869920495893927727E4,
8.29725251988426222434E4,
2.97683430363289370382E4,
4.15352677227719831579E3,
1.86145380837903397292E2,
1.0,
],
);
if const { P::POLICY.check_overflow } {
y1 = x0.cmp_lt(V::ONE).select(V::NAN, y1);
}
y2 = x_small.select(y1, y2);
}
y2
}
#[inline(always)]
fn atanh<P: Policy>(self) -> Self {
let x0 = self;
let x = x0.abs().flush_denormals::<P>();
let x_small = x.cmp_le(V::HALF);
let mut y2 = V::EMPTY;
if const { P::POLICY.avoid_branching } || !x_small.all() {
y2 = ((V::ONE + x) / (V::ONE - x)).ln_p::<P>().scale(0.5);
if const { P::POLICY.check_overflow } {
let y3 = x.cmp_eq(V::ONE).select(V::INFINITY, V::NAN);
y2 = x.cmp_ge(V::ONE).select(y3, y2);
}
if const { P::POLICY.avoid_precision_branches() } {
return y2.mul_sign(x0);
}
}
if const { P::POLICY.avoid_branching } || x_small.any() {
let x2 = x * x;
let y1 = x2
.poly_rational_p::<P, _, _>(
&[
-3.09092539379866942570E1,
6.54566728676544377376E1,
-4.61252884198732692637E1,
1.20426861384072379242E1,
-8.54074331929669305196E-1,
],
&[
-9.27277618139601130017E1,
2.52006675691344555838E2,
-2.49839401325893582852E2,
1.08938092147140262656E2,
-1.95638849376911654834E1,
1.0,
],
)
.mul_adde(x * x2, x);
y2 = x_small.select(y1, y2);
}
y2.mul_sign(x0)
}
#[inline(always)]
fn exp<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_EXP>(self)
}
#[inline(always)]
fn exph<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_EXPH>(self)
}
#[inline(always)]
fn exp2<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_POW2>(self)
}
#[inline(always)]
fn exp10<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_POW10>(self)
}
#[inline(always)]
fn exp_m1<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_EXPM1>(self)
}
#[inline(always)]
fn exp2_m1<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_POW2M1>(self)
}
#[inline(always)]
fn exp10_m1<P: Policy>(self) -> Self {
exp_d_internal::<Self, P, EXP_MODE_POW10M1>(self)
}
#[inline(always)]
fn powf<P: Policy>(self, y: Self) -> Self {
let x0 = self;
let ln2d_hi = crate::const_splat!(f64: 0.693145751953125); let ln2d_lo = crate::const_splat!(f64: 1.42860682030941723212E-6);
let x1 = x0.abs().flush_denormals::<P>();
let mut x = fraction2(x1);
let blend = x.cmp_gt(crate::const_splat!(f64: SQRT_2 / 2.0));
x.add_assign_c(!blend, x); x -= V::ONE;
let x2 = x * x;
#[rustfmt::skip]
let lg1 = (x2 * x) * x.poly_rational_p::<P, _, _>(
&[
2.0039553499201281259648E1,
5.7112963590585538103336E1,
6.0949667980987787057556E1,
2.9911919328553073277375E1,
6.5787325942061044846969E0,
4.9854102823193375972212E-1,
4.5270000862445199635215E-5,
],
&[
6.0118660497603843919306E1,
2.1642788614495947685003E2,
3.0909872225312059774938E2,
2.2176239823732856465394E2,
8.3047565967967209469434E1,
1.5062909083469192043167E1,
1.0,
],
);
let ef = exponent_f(x1).add_c(blend, V::ONE);
let e1 = (ef * y).round();
let yr = ef.mul_sube(y, e1);
let lg = V::HALF.nmul_adde(x2, x) + lg1;
let x2err = (V::HALF * x).mul_sube(x, V::HALF * x2);
let lgerr = V::HALF.mul_adde(x2, lg - x) - lg1;
let e2 = (lg * y).scale(FloatConsts::LOG2_E).round();
let mut v = e2.nmul_adde(ln2d_lo, lg.mul_sube(y, e2 * ln2d_hi));
v = yr.mul_adde(V::LN_2, v);
v = (lgerr + x2err).nmul_adde(y, v);
let mut x = v;
let e3 = x.scale(FloatConsts::LOG2_E).round();
x = e3.nmul_adde(V::LN_2, x);
let z = x.poly_rev_p::<P, _>(&[
1.0 / 6227020800.0,
1.0 / 479001600.0,
1.0 / 39916800.0,
1.0 / 3628800.0,
1.0 / 362880.0,
1.0 / 40320.0,
1.0 / 5040.0,
1.0 / 720.0,
1.0 / 120.0,
1.0 / 24.0,
1.0 / 6.0,
1.0 / 2.0,
1.0, 1.0, ]);
let ee = e1 + e2 + e3;
let ei: V::SignedBits = ee.fast_cast();
let ej = ei + (V::SignedBits::from_bits(z.abs()) >> 52);
let mut z = V::from_bits(V::SignedBits::from_bits(z) + (ei << 52));
if const { !P::POLICY.check_overflow } {
return y.cmp_eq(V::ZERO).select(V::ONE, z);
}
let overflow =
ej.cmp_ge(V::SignedBits::splat(0x07FF)).cast::<V::Mask>() | ee.cmp_gt(crate::const_splat!(f64: 3000.0));
let underflow =
ej.cmp_le(V::SignedBits::splat(0x0000)).cast::<V::Mask>() | ee.cmp_lt(crate::const_splat!(f64: -3000.0));
let xfinite = x0.is_finite();
let yfinite = y.is_finite();
let efinite = ee.is_finite();
let xzero = x0.is_zero_or_subnormal();
let xsign = x0.is_negative();
if crate::unlikely((overflow | underflow).any()) {
z = underflow.select(V::ZERO, z);
z = overflow.select(V::INFINITY, z);
}
let yzero = y.cmp_eq(V::ZERO);
let yneg = y.cmp_lt(V::ZERO);
z = xzero.select(yneg.select(V::INFINITY, yzero.select(V::ONE, V::ZERO)), z);
let mut yodd = V::ZERO;
if xsign.any() {
let yint = y.cmp_eq(y.round());
yodd = V::from_bits(y.into_bits::<V::Bits>() << 63);
let z1 = yint.select(z | yodd, x0.cmp_eq(V::ZERO).select(z, V::NAN));
yodd = yint.select(yodd, V::ZERO);
z = xsign.select(z1, z);
}
z = yzero.select(V::ONE, z);
let not_special = xfinite & yfinite & (efinite | xzero);
if crate::likely(not_special.all()) {
return z; }
let z1 = (yfinite & efinite).select(
z,
x1.cmp_eq(V::ONE).select(
V::ONE,
(x1.cmp_gt(V::ONE) ^ y.is_negative()).select(V::INFINITY, V::ZERO),
),
);
let z1 = xfinite.select(
z1,
yzero.select(
V::ONE,
yneg.select(
yodd & z, x1 | (x0 & yodd), ),
),
);
(x0.is_nan() | y.is_nan()).select(x0 + y, z1)
}
#[inline(always)]
fn cbrt<P: Policy>(self) -> Self {
let x = self.flush_denormals::<P>();
let b1 = crate::const_splat!(u64: 715094163); let b2 = crate::const_splat!(u64: 696219795); let m = crate::const_splat!(u64: 0x7fffffff);
let x1p54 = x * Self::splat(f64::from_bits(0x4350000000000000));
let hx0 = (x.into_bits::<V::Bits>() >> 32) & m;
let x_small = hx0.cmp_lt(V::Bits::splat(0x00100000));
let xs = x_small.select(x1p54, x); let b = x_small.select(b2, b1);
let mut ui: V::Bits = xs.into_bits();
let mut hx: V::Bits = (ui >> 32) & m;
hx = hx / Divider::u64(3) + b;
ui &= V::Bits::splat(1 << 63);
ui |= hx << 32;
let mut t = Self::from_bits(ui);
let r = (t * t) * (t / x);
t *= r.poly_p::<P, _>(&[
1.87595182427177009643,
-1.88497979543377169875,
1.621429720105354466140,
-0.758397934778766047437,
0.145996192886612446982,
]);
ui = t.into_bits();
ui = (ui + V::Bits::splat(0x80000000)) & V::Bits::splat(0xffffffffc0000000);
t = Self::from_bits(ui);
let r = if const {
P::POLICY.precision.ge(PrecisionPolicy::Best)
|| !Self::HAS_TRUE_FMA
|| matches!(P::POLICY.denormal_behavior, DenormalBehavior::Preserve)
} {
let xtt = x / (t * t);
(xtt - t) / ((t + t) + xtt)
} else if const { P::POLICY.precision.ge(PrecisionPolicy::Average) } {
let t3q = (t * t) * (t * Self::FRAC_1_4); let xq = x * Self::FRAC_1_4;
(xq - t3q) / t3q.mul_add(Self::TWO, xq)
} else {
let t3 = t * t * t;
(x - t3) / t3.mul_add(Self::TWO, x)
};
t = r.mul_adde(t, t);
if const { !P::POLICY.check_overflow } {
return x.cmp_eq(Self::ZERO).select(x, t);
}
let non_finite = hx0.cmp_ge(V::Bits::splat(0x7ff00000)).cast::<Self::Mask>();
(non_finite | x.cmp_eq(Self::ZERO)).select(x, t)
}
#[inline(always)]
fn ln<P: Policy>(self) -> Self {
ln_d_internal::<Self, P, false>(self)
}
#[inline(always)]
fn ln_1p<P: Policy>(self) -> Self {
ln_d_internal::<Self, P, true>(self)
}
#[inline(always)]
fn log2<P: Policy>(self) -> Self {
ln_d_internal::<Self, P, false>(self).scale(FloatConsts::LOG2_E)
}
#[inline(always)]
fn log10<P: Policy>(self) -> Self {
ln_d_internal::<Self, P, false>(self).scale(FloatConsts::LOG10_E)
}
#[inline(always)]
fn ln1m_expnx<P: Policy>(self) -> Self {
(V::ONE - (-self).exp_p::<P>()).ln_p::<P>()
}
#[inline(always)]
fn ln1m_expnx_ext<P: Policy>(self, _lnx: Self) -> Self {
(V::ONE - (-self).exp_p::<P>()).ln_p::<P>()
}
}
#[inline(always)]
fn fraction2<V: FloatVectorWithBits<Element = f64>>(x: V) -> V {
(x & crate::const_splat!(f64: f64::from_bits(0x000FFFFFFFFFFFFF)))
| crate::const_splat!(f64: f64::from_bits(0x3FE0000000000000))
}
#[inline(always)]
fn exponent<V: FloatVectorWithBits<Element = f64>>(x: V) -> V::SignedBits {
V::SignedBits::from_bits((V::Bits::from_bits(x) << 1) >> 53) - V::SignedBits::splat(0x3FF)
}
#[inline(always)]
fn exponent_f<V: FloatVectorWithBits<Element = f64>>(x: V) -> V {
let pow2_52: V = crate::const_splat!(f64: 4503599627370496.0);
let bias: V = crate::const_splat!(f64: 1023.0);
V::from_bits((V::Bits::from_bits(x) >> 52) | pow2_52.into_bits()) - (pow2_52 + bias)
}
#[inline(always)]
fn ln_d_internal<V: FloatVectorWithBits<Element = f64>, P: Policy, const P1: bool>(x0: V) -> V {
let ln2_hi = crate::const_splat!(f64: 0.693359375);
let ln2_lo = crate::const_splat!(f64: -2.121944400546905827679E-4);
let mut x1 = if P1 { x0 + V::ONE } else { x0 };
let mut scaled = GenericMask::FALSY;
if const { matches!(P::POLICY.denormal_behavior, DenormalBehavior::Preserve) } {
scaled = x1.is_subnormal();
x1 = x1.mul_c(scaled, crate::const_splat!(f64: hexf::hexf64!("0x1.0p54")));
}
let mut x = fraction2::<V>(x1);
let mut fe = V::cast_from(exponent::<V>(x1));
let blend = x.cmp_gt(crate::const_splat!(f64: SQRT_2 * 0.5));
x = x.add_c(!blend, x);
fe = fe.add_c(blend, V::ONE);
if const { matches!(P::POLICY.denormal_behavior, DenormalBehavior::Preserve) } {
fe = fe.sub_c(scaled, crate::const_splat!(f64: 54.0));
}
let xp1 = x - V::ONE;
x = if P1 {
fe.cmp_eq(V::ZERO).select(x0, xp1)
} else {
xp1
};
let x2 = x * x;
let x3 = x * x2;
let mut res =
x3 * x.poly_p::<P, _>(&[
7.70838733755885391666E0,
1.79368678507819816313E1,
1.44989225341610930846E1,
4.70579119878881725854E0,
4.97494994976747001425E-1,
1.01875663804580931796E-4,
]) / x.poly_p::<P, _>(&[
2.31251620126765340583E1,
7.11544750618563894466E1,
8.29875266912776603211E1,
4.52279145837532221105E1,
1.12873587189167450590E1,
1.0,
]);
res = fe.mul_adde(ln2_lo, res); res += x2.nmul_adde(V::HALF, x); res = fe.mul_adde(ln2_hi, res);
if const { !P::POLICY.check_overflow } {
return res;
}
let overflow = !x1.is_finite();
let underflow = x1.cmp_lt(crate::const_splat!(f64: 2.2250738585072014E-308));
if const { !P::POLICY.avoid_branching } && crate::likely((overflow | underflow).none()) {
return res;
}
res = underflow.select(V::NAN, res); res = x1.is_zero_or_subnormal().select(V::NEG_INFINITY, res); res = overflow.select(x1, res); res = (x1.is_infinite() & x1.is_negative()).select(V::NAN, res);
res
}
#[inline(always)]
fn atan_internal<V: FloatVectorWithBits<Element = f64>, P: Policy, const ATAN2: bool>(y: V, x: V) -> V {
let morebits: V = crate::const_splat!(f64: 6.123233995736765886130E-17);
let morebitso2: V = crate::const_splat!(f64: 6.123233995736765886130E-17 * 0.5);
let t3po8: V = crate::const_splat!(f64: SQRT_2 + 1.0);
let mut swapxy = GenericMask::FALSY;
let t = if ATAN2 {
let x1 = x.abs().flush_denormals::<P>();
let y1 = y.abs().flush_denormals::<P>();
swapxy = y1.cmp_gt(x1);
let mut x2 = swapxy.select(y1, x1);
let mut y2 = swapxy.select(x1, y1);
if const { P::POLICY.check_overflow } {
let both_inf = x.is_infinite() & y.is_infinite();
if crate::unlikely(both_inf.any()) {
x2 = both_inf.select(x2 & V::NEG_ONE, x2);
y2 = both_inf.select(y2 & V::NEG_ONE, y2);
}
}
y2 / x2
} else {
y.abs()
};
let t = t.flush_denormals::<P>();
let not_big = t.cmp_le(t3po8);
let not_small = t.cmp_ge(crate::const_splat!(f64: 0.66));
let s = not_big.select(V::FRAC_PI_4, V::FRAC_PI_2);
let fac = not_big.select(morebitso2, morebits);
let a = V::NEG_ONE.zz(not_small).add_c(not_big, t);
let b = V::ONE.zz(not_big).add_c(not_small, t);
let z = a / b;
let zz = z * z;
let re0 = zz.poly_p::<P, _>(&[
-6.485021904942025371773E1,
-1.228866684490136173410E2,
-7.500855792314704667340E1,
-1.615753718733365076637E1,
-8.750608600031904122785E-1,
]) / zz.poly_p::<P, _>(&[
1.945506571482613964425E2,
4.853903996359136964868E2,
4.328810604912902668951E2,
1.650270098316988542046E2,
2.485846490142306297962E1,
1.0,
]);
let mut re = re0.mul_adde(z * zz, z.add_c(not_small, s).add_c(not_small, fac));
if ATAN2 {
re = swapxy.select(V::FRAC_PI_2 - re, re);
re = (x | y).cmp_eq(V::ZERO).select(V::ZERO, re); re = x.select_negative(V::PI - re, re);
}
re.mul_sign(y)
}
#[inline(always)]
fn asin_internal<V: FloatVectorWithBits<Element = f64>, P: Policy, const ACOS: bool>(x: V) -> V {
let xa = x.abs().flush_denormals::<P>();
let is_big = xa.cmp_ge(crate::const_splat!(f64: 0.625));
let x1 = is_big.select(V::ONE - xa, xa * xa);
let mut px = V::EMPTY;
let mut qx = V::EMPTY;
let mut rx = V::EMPTY;
let mut sx = V::EMPTY;
let mut xb = V::EMPTY;
if const { P::POLICY.avoid_branching } || !is_big.all() {
px = x1.poly_rev_p::<P, _>(&[
4.253011369004428248960E-3,
-6.019598008014123785661E-1,
5.444622390564711410273E0,
-1.626247967210700244449E1,
1.956261983317594739197E1,
-8.198089802484824371615E0,
]);
qx = x1.poly_rev_p::<P, _>(&[
1.0,
-1.474091372988853791896E1,
7.049610280856842141659E1,
-1.471791292232726029859E2,
1.395105614657485689735E2,
-4.918853881490881290097E1,
]);
}
if const { P::POLICY.avoid_branching } || is_big.any() {
xb = (x1 + x1).sqrt();
rx = x1.poly_p::<P, _>(&[
2.853665548261061424989E1,
-2.556901049652824852289E1,
6.968710824104713396794E0,
-5.634242780008963776856E-1,
2.967721961301243206100E-3,
]);
sx = x1.poly_p::<P, _>(&[
3.424398657913078477438E2,
-3.838770957603691357202E2,
1.470656354026814941758E2,
-2.194779531642920639778E1,
1.0,
]);
}
let vx = is_big.select(rx, px);
let wx = is_big.select(sx, qx);
let y1 = vx / wx * x1;
let z1 = xb.mul_adde(y1, xb);
let z2 = xa.mul_adde(y1, xa);
if ACOS {
let z1 = x.select_negative(V::PI - z1, z1);
let z2 = V::FRAC_PI_2 - z2.mul_sign(x);
is_big.select(z1, z2)
} else {
let z1 = V::FRAC_PI_2 - z1;
is_big.select(z1, z2).mul_sign(x)
}
}
#[inline(always)]
fn pow2n_d<V: FloatVectorWithBits<Element = f64>>(n: V) -> V {
let pow2_52: V = crate::const_splat!(f64: 4503599627370496.0);
let bias: V = crate::const_splat!(f64: 1023.0);
V::from_bits(V::Bits::from_bits(n + (bias + pow2_52)) << 52)
}
#[inline(always)]
fn exp_d_internal<V: FloatVectorWithBits<Element = f64>, P: Policy, const MODE: u8>(x0: V) -> V {
let mut x = x0.flush_denormals::<P>();
let mut r;
let max_x;
match MODE {
EXP_MODE_POW2 | EXP_MODE_POW2M1 => {
max_x = 1022.0;
r = x.round();
x -= r;
x *= V::LN_2;
}
EXP_MODE_POW10 | EXP_MODE_POW10M1 => {
max_x = 307.65;
let log10_2_hi: V = crate::const_splat!(f64: -0.30102999554947019); let log10_2_lo: V = crate::const_splat!(f64: -1.1451100899212592E-10);
r = (x * crate::const_splat!(f64: LN_10 * LOG2_E)).round();
x = r.mul_adde(log10_2_hi, x); x = r.mul_adde(log10_2_lo, x); x *= V::LN_10;
}
_ => {
max_x = const { if MODE == EXP_MODE_EXP { 708.39 } else { 709.7 } };
let ln2d_hi: V = crate::const_splat!(f64: -0.693145751953125);
let ln2d_lo: V = crate::const_splat!(f64: -1.42860682030941723212E-6);
r = (x * crate::const_splat!(f64: LOG2_E)).round();
x = r.mul_adde(ln2d_hi, x); x = r.mul_adde(ln2d_lo, x);
if MODE == EXP_MODE_EXPH {
r -= V::ONE;
}
}
}
let mut z = x.poly_p::<P, _>(&[
0.0,
1.0,
1.0 / 2.0,
1.0 / 6.0,
1.0 / 24.0,
1.0 / 120.0,
1.0 / 720.0,
1.0 / 5040.0,
1.0 / 40320.0,
1.0 / 362880.0,
1.0 / 3628800.0,
1.0 / 39916800.0,
1.0 / 479001600.0,
1.0 / 6227020800.0,
]);
if const { !P::POLICY.check_overflow } {
r = r.clamp(crate::const_splat!(f64: -1023.0), crate::const_splat!(f64: 1023.0));
}
let n2 = pow2n_d::<V>(r);
z = match MODE {
EXP_MODE_EXPM1 | EXP_MODE_POW2M1 | EXP_MODE_POW10M1 => z.mul_adde(n2, n2 - V::ONE),
_ => z.mul_adde(n2, n2), };
if const { P::POLICY.check_overflow } {
let in_range = x0.abs().cmp_lt(V::splat(max_x)) & x0.is_finite();
if crate::likely(in_range.all()) {
return z;
}
let underflow_value = const {
if MODE == EXP_MODE_EXPM1 || MODE == EXP_MODE_POW2M1 || MODE == EXP_MODE_POW10M1 {
V::NEG_ONE
} else {
V::ZERO
}
};
r = x0.select_negative(underflow_value, V::INFINITY);
z = in_range.select(z, r);
z = x0.is_nan().select(x0, z);
}
z
}
#[thermite_macros::dispatch(V, thermite = "crate")]
fn payne_hanek_reduction<P: Policy, V: FloatVectorWithBits<Element = f64>>(xa: &V) -> (V, V, V::Bits) {
let xa_bits: V::Bits = xa.into_bits();
let exp =
(V::SignedBits::from_bits(xa_bits.shri::<52>()) & V::SignedBits::splat(0x7FF)) - V::SignedBits::splat(1023);
let exp_u: V::Unsigned = V::Bits::from_bits(exp.max(V::SignedBits::ZERO)).cast();
let sig = (xa_bits & V::Bits::splat(0x000F_FFFF_FFFF_FFFF)) | V::Bits::splat(0x0010_0000_0000_0000);
const INVPI_TABLE: [u64; 19] = [
0x0000000000000000, 0xA2F9836E4E441529,
0xFC2757D1F534DDC0,
0xDB6295993C439041,
0xFE5163ABDEBBC561,
0xB7246E3A424DD2E0,
0x06492EEA09D1921C,
0xFE1DEB1CB129A73E,
0xE88235F52EBB4484,
0xE99C7026B45F7E41,
0x3991D639835339F4,
0x9C845F8BBDF9283B,
0x1FF897FFDE05980F,
0xEF2F118B5A0A6D1F,
0x6D367ECF27CB09B7,
0x4F463F669E5FEA2D,
0x7527BAC7EBE5F17B,
0x3D0739F78A5292EA,
0x6BFB5FB11F8D5D08,
];
let biased = exp_u + V::Unsigned::splat(9); let idx: V::Unsigned = biased.shri::<6>();
let shift = biased & V::Unsigned::splat(63);
let inv_shift = (V::Unsigned::splat(64) - shift) & V::Unsigned::splat(63);
let c0 = unsafe { V::Unsigned::lookup_unchecked(&INVPI_TABLE, idx) };
let c1 = unsafe { V::Unsigned::lookup_unchecked(&INVPI_TABLE, idx + V::Unsigned::ONE) };
let c2 = unsafe { V::Unsigned::lookup_unchecked(&INVPI_TABLE, idx + V::Unsigned::TWO) };
let mask = shift.cmp_ne(V::Unsigned::ZERO);
let aligned_hi = c0.shlv(shift) | c1.shrv(inv_shift).zz(mask);
let aligned_lo = c1.shlv(shift) | c2.shrv(inv_shift).zz(mask);
let aligned_hi: V::Bits = aligned_hi.cast();
let aligned_lo: V::Bits = aligned_lo.cast();
let prod_hi = sig.mullo(aligned_hi); let prod_lo = sig.mulhi(aligned_lo); let mid_bits = prod_hi + prod_lo; let prod_lo_lo = sig.mullo(aligned_lo);
let mut q_ph: V::Bits = mid_bits.shri::<61>() & V::Bits::splat(3);
let fraction_hi_int = mid_bits & V::Bits::splat(0x1FFF_FFFF_FFFF_FFFF);
let frac_hi_bits = fraction_hi_int.shri::<9>() | V::Bits::splat(0x3FF0_0000_0000_0000);
let frac_hi = V::from_bits(frac_hi_bits) - V::ONE;
let residual = (fraction_hi_int & V::Bits::splat(0x1FF)).shli::<43>() | prod_lo_lo.shri::<21>();
let frac_lo_int: V::SignedBits = residual.cast();
let frac_lo = V::cast_from(frac_lo_int) * crate::const_splat!(f64: hexf::hexf64!("0x1.0p-104"));
let needs_round = frac_hi.cmp_ge(V::HALF);
let frac_hi = frac_hi.sub_c(needs_round, V::ONE);
q_ph = q_ph.add_c(needs_round.cast(), V::Bits::ONE);
let pi2_hi = V::FRAC_PI_2;
let pi2_lo = crate::const_splat!(f64: 6.123233995736766e-17);
let x_hi = frac_hi * pi2_hi;
let x_lo = frac_hi.mul_add(pi2_hi, -x_hi) + frac_hi * pi2_lo + frac_lo * pi2_hi;
(x_hi, x_lo, q_ph)
}
#[inline(always)]
pub(crate) fn trig_range_reduction<P: Policy, V: FloatVectorWithBits<Element = f64>, const PI: bool>(
mut xa: V,
) -> (V, V, V::Bits) {
let mut is_large = V::Mask::FALSY;
let y = if PI {
xa + xa } else {
is_large = xa.cmp_gt(if const { P::POLICY.precision.gt(PrecisionPolicy::Average) } {
crate::const_splat!(<V> = <V: FloatVectorWithBits> f64: {
match V::HAS_TRUE_FMA {
true => 1e15,
false => 1e7,
}
})
} else {
crate::const_splat!(<V> = <V: FloatVectorWithBits> f64: {
match V::HAS_TRUE_FMA {
true => 1e15,
false => 1e13,
}
})
});
if const { P::POLICY.check_overflow && P::POLICY.precision.le(PrecisionPolicy::Average) } {
xa = xa.nz(is_large); }
xa.scale(FloatConsts::FRAC_2_PI)
};
let y = y.round();
let mut q = V::Bits::fast_cast_from(y);
let dp1 = crate::const_splat!(f64: 7.853981554508209228515625E-1 * 2.0);
let dp2 = crate::const_splat!(f64: 7.94662735614792836714E-9 * 2.0);
let dp3 = crate::const_splat!(f64: 3.06161699786838294307E-17 * 2.0);
let mut x = if PI {
y.nmul_adde(V::HALF, xa).scale(FloatConsts::PI)
} else if const { V::HAS_TRUE_FMA } {
y.nmul_add(dp3, y.nmul_add(dp2 + dp1, xa))
} else {
((xa - y * dp1) - y * dp2) - y * dp3
};
let mut x_lo = V::ZERO;
if const { P::POLICY.precision.gt(PrecisionPolicy::Average) && !PI }
&& (P::POLICY.avoid_branching || is_large.any())
{
let is_large = is_large & xa.is_finite();
let (x_ph, x_lo_ph, q_ph) = payne_hanek_reduction::<P, V>(&xa);
x = is_large.select(x_ph, x);
x_lo = x_lo_ph.zz(is_large); q = is_large.select(q_ph, q);
}
(x, x_lo, q)
}
#[inline(always)]
fn sincos_d_internal<P: Policy, V: FloatVectorWithBits<Element = f64>, const PI: bool>(xx: V) -> (V, V) {
let xa = xx.abs().flush_denormals::<P>();
let (x, x_lo, q) = trig_range_reduction::<P, V, PI>(xa);
let x2 = x * x;
let x4 = x2 * x2;
let mut s = x2.poly_rev_p::<P, _>(&[
1.58962301576546568060E-10,
-2.50507477628578072866E-8,
2.75573136213857245213E-6,
-1.98412698295895385996E-4,
8.33333333332211858878E-3,
-1.66666666666666307295E-1,
]);
let mut c = x2.poly_rev_p::<P, _>(&[
-1.13585365213876817300E-11,
2.08757008419747316778E-9,
-2.75573141792967388112E-7,
2.48015872888517045348E-5,
-1.38888888888730564116E-3,
4.16666666666665929218E-2,
]);
let mut x0 = x;
if const { P::POLICY.precision.ge(PrecisionPolicy::Best) } {
x0 += x_lo; }
s = s.mul_adde(x2 * x, x0); c = c.mul_adde(x4, x2.nmul_adde(V::HALF, V::ONE));
if const { P::POLICY.precision.ge(PrecisionPolicy::Best) } {
c = x.nmul_adde(x_lo, c); }
let swap = (q & V::Bits::ONE).cmp_ne(V::Bits::ZERO);
if const { P::POLICY.check_overflow } {
let overflow = q.cmp_gt(V::Bits::splat((1u64 << 52) - 1)).cast::<V::Mask>() & xa.is_finite();
s = s.nz(overflow); c = overflow.select(V::ONE, c);
}
let sin1 = swap.select(c, s);
let cos1 = swap.select(s, c);
let signsin = V::from_bits(q << 62) ^ xx;
let signcos = V::from_bits(((q + V::Bits::ONE) & V::Bits::splat(2)) << 62);
(sin1.mul_sign(signsin), cos1 ^ signcos)
}