1use crate::acospi::INV_PI_DD;
30use crate::asin::asin_eval;
31use crate::asin_eval_dyadic::asin_eval_dyadic;
32use crate::common::{dd_fmla, dyad_fmla, f_fmla};
33use crate::double_double::DoubleDouble;
34use crate::dyadic_float::{DyadicFloat128, DyadicSign};
35use crate::round::RoundFinite;
36
37pub fn f_asinpi(x: f64) -> f64 {
41 let x_e = (x.to_bits() >> 52) & 0x7ff;
42 const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64;
43
44 let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff);
45
46 if x_e < E_BIAS - 1 {
48 if x_e < E_BIAS - 26 {
50 if x.abs() == 0. {
58 return x;
59 }
60
61 if x_e < E_BIAS - 56 {
62 if (x_abs.to_bits().wrapping_shl(12)) == 0x59af9a1194efe000u64 {
63 let e = (x.to_bits() >> 52) & 0x7ff;
64 let h = f64::from_bits(0x3c7b824198b94a89);
65 let l = f64::from_bits(0x391fffffffffffff);
66 let mut t = (if x > 0. { 1.0f64 } else { -1.0f64 }).to_bits();
67 t = t.wrapping_sub(0x3c9u64.wrapping_sub(e).wrapping_shl(52));
68 return f_fmla(l, f64::from_bits(t), h * f64::from_bits(t));
69 }
70
71 let h = x * INV_PI_DD.hi;
72 let sx = x * f64::from_bits(0x4690000000000000); let mut l = dd_fmla(sx, INV_PI_DD.hi, -h * f64::from_bits(0x4690000000000000));
74 l = dd_fmla(sx, INV_PI_DD.lo, l);
75 let res = dyad_fmla(l, f64::from_bits(0x3950000000000000), h);
77 return res;
78 }
79
80 const C1H: f64 = f64::from_bits(0x3fd45f306dc9c883);
84 const C1L: f64 = f64::from_bits(0xbc76b01ec5417057);
85 const C3: f64 = f64::from_bits(0x3fab2995e7b7b606);
86 let h = C1H;
87 let l = dd_fmla(C3, x * x, C1L);
88 let hh = h * x;
90 let mut ll = dd_fmla(h, x, -hh);
91 ll = dd_fmla(l, x, ll);
93 return hh + ll;
94 }
95
96 let x_sq = DoubleDouble::from_exact_mult(x, x);
97 let err = x_abs * f64::from_bits(0x3cc0000000000000);
98 let (p, err) = asin_eval(x_sq, err);
102 let mut r0 = DoubleDouble::from_exact_mult(x, p.hi);
104 let mut r_lo = f_fmla(x, p.lo, r0.lo);
105
106 r0 = DoubleDouble::mult(DoubleDouble::new(r_lo, r0.hi), INV_PI_DD);
107 r_lo = r0.lo;
108
109 let r_upper = r0.hi + (r_lo + err);
110 let r_lower = r0.hi + (r_lo - err);
111
112 if r_upper == r_lower {
113 return r_upper;
114 }
115
116 let idx = (x_sq.hi * f64::from_bits(0x4050000000000000)).round_finite() as usize;
120
121 let x_f128 = DyadicFloat128::new_from_f64(x);
125
126 let u: DyadicFloat128;
127 #[cfg(any(
128 all(
129 any(target_arch = "x86", target_arch = "x86_64"),
130 target_feature = "fma"
131 ),
132 all(target_arch = "aarch64", target_feature = "neon")
133 ))]
134 {
135 let u_hi = DyadicFloat128::new_from_f64(f_fmla(
137 idx as f64,
138 f64::from_bits(0xbf90000000000000),
139 x_sq.hi,
140 ));
141 u = u_hi.quick_add(&DyadicFloat128::new_from_f64(x_sq.lo));
142 }
143
144 #[cfg(not(any(
145 all(
146 any(target_arch = "x86", target_arch = "x86_64"),
147 target_feature = "fma"
148 ),
149 all(target_arch = "aarch64", target_feature = "neon")
150 )))]
151 {
152 let x_sq_f128 = x_f128.quick_mul(&x_f128);
153 u = x_sq_f128.quick_add(&DyadicFloat128::new_from_f64(
154 idx as f64 * (f64::from_bits(0xbf90000000000000)),
155 ));
156 }
157
158 let p_f128 = asin_eval_dyadic(u, idx);
159 let mut r = x_f128.quick_mul(&p_f128);
160 r = r.quick_mul(&crate::acospi::INV_PI_F128);
161 return r.fast_as_f64();
162 }
163
164 const PI_OVER_TWO: DoubleDouble = DoubleDouble::new(
165 f64::from_bits(0x3c91a62633145c07),
166 f64::from_bits(0x3ff921fb54442d18),
167 );
168
169 let x_sign = if x.is_sign_negative() { -1.0 } else { 1.0 };
170
171 if x_e >= E_BIAS {
173 if x_abs == 1.0 {
175 return x * 0.5; }
178 if x.is_nan() {
180 return x;
181 }
182 return f64::NAN;
183 }
184
185 let u = f_fmla(x_abs, -0.5, 0.5);
187 let v_hi = u.sqrt();
198 let h;
199 #[cfg(any(
200 all(
201 any(target_arch = "x86", target_arch = "x86_64"),
202 target_feature = "fma"
203 ),
204 all(target_arch = "aarch64", target_feature = "neon")
205 ))]
206 {
207 h = f_fmla(v_hi, -v_hi, u);
208 }
209 #[cfg(not(any(
210 all(
211 any(target_arch = "x86", target_arch = "x86_64"),
212 target_feature = "fma"
213 ),
214 all(target_arch = "aarch64", target_feature = "neon")
215 )))]
216 {
217 let v_hi_sq = DoubleDouble::from_exact_mult(v_hi, v_hi);
218 h = (u - v_hi_sq.hi) - v_hi_sq.lo;
219 }
220 let vh = v_hi * 2.0;
224 let vl = h / v_hi;
225
226 let err = vh * f64::from_bits(0x3cc0000000000000);
229
230 let (p, err) = asin_eval(DoubleDouble::new(0.0, u), err);
231
232 let r0 = DoubleDouble::quick_mult(DoubleDouble::new(vl, vh), p);
235 let mut r = DoubleDouble::from_exact_add(PI_OVER_TWO.hi, -r0.hi);
236
237 let mut r_lo = PI_OVER_TWO.lo - r0.lo + r.lo;
238
239 let p = DoubleDouble::mult(DoubleDouble::new(r_lo, r.hi), INV_PI_DD);
240 r_lo = p.lo;
241 r.hi = p.hi;
242
243 let (r_upper, r_lower);
244
245 #[cfg(any(
246 all(
247 any(target_arch = "x86", target_arch = "x86_64"),
248 target_feature = "fma"
249 ),
250 all(target_arch = "aarch64", target_feature = "neon")
251 ))]
252 {
253 r_upper = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, err));
254 r_lower = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, -err));
255 }
256 #[cfg(not(any(
257 all(
258 any(target_arch = "x86", target_arch = "x86_64"),
259 target_feature = "fma"
260 ),
261 all(target_arch = "aarch64", target_feature = "neon")
262 )))]
263 {
264 let r_lo = r_lo * x_sign;
265 let r_hi = r.hi * x_sign;
266 r_upper = r_hi + (r_lo + err);
267 r_lower = r.hi + (r_lo - err);
268 }
269
270 if r_upper == r_lower {
271 return r_upper;
272 }
273
274 let idx = (u * f64::from_bits(0x4050000000000000)).round_finite() as usize;
277
278 let vl_lo;
298 #[cfg(any(
299 all(
300 any(target_arch = "x86", target_arch = "x86_64"),
301 target_feature = "fma"
302 ),
303 all(target_arch = "aarch64", target_feature = "neon")
304 ))]
305 {
306 vl_lo = f_fmla(-v_hi, vl, h) / v_hi;
307 }
308 #[cfg(not(any(
309 all(
310 any(target_arch = "x86", target_arch = "x86_64"),
311 target_feature = "fma"
312 ),
313 all(target_arch = "aarch64", target_feature = "neon")
314 )))]
315 {
316 let vh_vl = DoubleDouble::from_exact_mult(v_hi, vl);
317 vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi;
318 }
319
320 let t = h * (-0.25) / u;
322 let vll = f_fmla(vl, t, vl_lo);
323 let mv0 = DyadicFloat128::new_from_f64(vl) + DyadicFloat128::new_from_f64(vll);
325 let mut m_v = DyadicFloat128::new_from_f64(vh) + mv0;
326 m_v.sign = DyadicSign::Neg;
327
328 let y_f128 =
331 DyadicFloat128::new_from_f64(f_fmla(idx as f64, f64::from_bits(0xbf90000000000000), u));
332
333 const PI_OVER_TWO_F128: DyadicFloat128 = DyadicFloat128 {
334 sign: DyadicSign::Pos,
335 exponent: -127,
336 mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,
337 };
338
339 let p_f128 = asin_eval_dyadic(y_f128, idx);
340 let r0_f128 = m_v * p_f128;
341 let mut r_f128 = PI_OVER_TWO_F128 + r0_f128;
342
343 if x.is_sign_negative() {
344 r_f128.sign = DyadicSign::Neg;
345 }
346
347 r_f128 = r_f128.quick_mul(&crate::acospi::INV_PI_F128);
348
349 r_f128.fast_as_f64()
350}
351
352#[cfg(test)]
353mod tests {
354 use super::*;
355
356 #[test]
357 fn f_asinpi_test() {
358 assert_eq!(
359 f_asinpi(-0.00000000032681723993732703),
360 -0.00000000010402915844735117
361 );
362 assert_eq!(f_asinpi(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017801371778309684), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005666352624669099);
363 assert_eq!(f_asinpi(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026752519513526076), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008515591441480124);
364 assert_eq!(f_asinpi(-0.4), -0.13098988043445461);
365 assert_eq!(f_asinpi(-0.8), -0.2951672353008666);
366 assert_eq!(f_asinpi(0.4332432142124432), 0.14263088583055605);
367 assert_eq!(f_asinpi(0.8543543534343434), 0.326047108714517);
368 assert_eq!(f_asinpi(0.00323146509843243), 0.0010286090778797426);
369 }
370}