1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse2")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
12 #[repr(C, align(16))]
13 pub struct f64x2 { pub(crate) sse: m128d }
14 } else if #[cfg(target_feature="simd128")] {
15 use core::arch::wasm32::*;
16
17 #[derive(Clone, Copy)]
24 #[repr(transparent)]
25 pub struct f64x2 { pub(crate) simd: v128 }
26
27 impl Default for f64x2 {
28 fn default() -> Self {
29 Self::splat(0.0)
30 }
31 }
32
33 impl PartialEq for f64x2 {
34 fn eq(&self, other: &Self) -> bool {
35 u64x2_all_true(f64x2_eq(self.simd, other.simd))
36 }
37 }
38 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
39 use core::arch::aarch64::*;
40
41 #[repr(C)]
48 #[derive(Copy, Clone)]
49 pub struct f64x2 { pub(crate) neon: float64x2_t }
50
51 impl Default for f64x2 {
52 #[inline]
53 fn default() -> Self {
54 unsafe { Self { neon: vdupq_n_f64(0.0)} }
55 }
56 }
57
58 impl PartialEq for f64x2 {
59 #[inline]
60 fn eq(&self, other: &Self) -> bool {
61 unsafe
62 { let e = vceqq_f64(self.neon, other.neon);
63 vgetq_lane_u64(e,0) == u64::MAX && vgetq_lane_u64(e,1) == u64::MAX
64 }
65 }
66
67 }
68 } else {
69 #[derive(Default, Clone, Copy, PartialEq)]
76 #[repr(C, align(16))]
77 pub struct f64x2 { pub(crate) arr: [f64;2] }
78 }
79}
80
81macro_rules! const_f64_as_f64x2 {
82 ($i:ident, $f:expr) => {
83 #[allow(non_upper_case_globals)]
84 pub const $i: f64x2 = f64x2::new([$f; 2]);
85 };
86}
87
88impl_simd_float! {
89 unsafe {
90 T = f64,
91 N = 2,
92 Simd = f64x2,
93 IntSimd = i64x2,
94 UintT = u64,
95 UintSimd = u64x2,
96 optional_type_x86_inner { X86Inner = __m128d },
97 optional_type_arm_inner { ArmInner = float64x2_t },
98 optional_type_wasm_inner { WasmInner = v128 },
99 }
100 old_powf_simd_fn_name = pow_f64x2,
101
102 #[inline]
103 fn neg(self) -> Self::Output {
104 pick! {
105 if #[cfg(target_feature="sse")] {
106 Self { sse: bitxor_m128d(self.sse, Self::splat(-0.0).sse) }
107 } else if #[cfg(target_feature="simd128")] {
108 Self { simd: f64x2_neg(self.simd) }
109 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
110 unsafe {Self { neon: vnegq_f64(self.neon) }}
111 } else {
112 Self { arr: [
113 -self.arr[0],
114 -self.arr[1],
115 ]}
116 }
117 }
118 }
119
120 #[inline]
121 fn not(self) -> Self {
122 pick! {
123 if #[cfg(target_feature="sse2")] {
124 Self { sse: self.sse.not() }
125 } else if #[cfg(target_feature="simd128")] {
126 Self { simd: v128_not(self.simd) }
127 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
128 unsafe {Self { neon: vreinterpretq_f64_u32(vmvnq_u32(vreinterpretq_u32_f64(self.neon))) }}
129 } else {
130 Self { arr: [
131 f64::from_bits(!self.arr[0].to_bits()),
132 f64::from_bits(!self.arr[1].to_bits()),
133 ]}
134 }
135 }
136 }
137
138 #[inline]
139 fn add(self, rhs: Self) -> Self::Output {
140 pick! {
141 if #[cfg(target_feature="sse2")] {
142 Self { sse: add_m128d(self.sse, rhs.sse) }
143 } else if #[cfg(target_feature="simd128")] {
144 Self { simd: f64x2_add(self.simd, rhs.simd) }
145 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
146 unsafe { Self { neon: vaddq_f64(self.neon, rhs.neon) } }
147 } else {
148 Self { arr: [
149 self.arr[0] + rhs.arr[0],
150 self.arr[1] + rhs.arr[1],
151 ]}
152 }
153 }
154 }
155
156 #[inline]
157 fn sub(self, rhs: Self) -> Self::Output {
158 pick! {
159 if #[cfg(target_feature="sse2")] {
160 Self { sse: sub_m128d(self.sse, rhs.sse) }
161 } else if #[cfg(target_feature="simd128")] {
162 Self { simd: f64x2_sub(self.simd, rhs.simd) }
163 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
164 unsafe { Self { neon: vsubq_f64(self.neon, rhs.neon) } }
165 } else {
166 Self { arr: [
167 self.arr[0] - rhs.arr[0],
168 self.arr[1] - rhs.arr[1],
169 ]}
170 }
171 }
172 }
173
174 #[inline]
175 fn mul(self, rhs: Self) -> Self::Output {
176 pick! {
177 if #[cfg(target_feature="sse2")] {
178 Self { sse: mul_m128d(self.sse, rhs.sse) }
179 } else if #[cfg(target_feature="simd128")] {
180 Self { simd: f64x2_mul(self.simd, rhs.simd) }
181 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
182 unsafe {Self { neon: vmulq_f64(self.neon, rhs.neon) }}
183 } else {
184 Self { arr: [
185 self.arr[0] * rhs.arr[0],
186 self.arr[1] * rhs.arr[1],
187 ]}
188 }
189 }
190 }
191
192 #[inline]
193 fn div(self, rhs: Self) -> Self::Output {
194 pick! {
195 if #[cfg(target_feature="sse2")] {
196 Self { sse: div_m128d(self.sse, rhs.sse) }
197 } else if #[cfg(target_feature="simd128")] {
198 Self { simd: f64x2_div(self.simd, rhs.simd) }
199 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
200 unsafe {Self { neon: vdivq_f64(self.neon, rhs.neon) }}
201 } else {
202 Self { arr: [
203 self.arr[0] / rhs.arr[0],
204 self.arr[1] / rhs.arr[1],
205 ]}
206 }
207 }
208 }
209
210 #[inline]
211 fn rem(self, rhs: Self) -> Self::Output {
212 Self::new([
213 self.to_array()[0] % rhs.to_array()[0],
214 self.to_array()[1] % rhs.to_array()[1],
215 ])
216 }
217
218 #[inline]
219 fn bitand(self, rhs: Self) -> Self::Output {
220 pick! {
221 if #[cfg(target_feature="sse2")] {
222 Self { sse: bitand_m128d(self.sse, rhs.sse) }
223 } else if #[cfg(target_feature="simd128")] {
224 Self { simd: v128_and(self.simd, rhs.simd) }
225 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
226 unsafe {Self { neon: vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
227 } else {
228 Self { arr: [
229 f64::from_bits(self.arr[0].to_bits() & rhs.arr[0].to_bits()),
230 f64::from_bits(self.arr[1].to_bits() & rhs.arr[1].to_bits()),
231 ]}
232 }
233 }
234 }
235
236 #[inline]
237 fn bitor(self, rhs: Self) -> Self::Output {
238 pick! {
239 if #[cfg(target_feature="sse2")] {
240 Self { sse: bitor_m128d(self.sse, rhs.sse) }
241 } else if #[cfg(target_feature="simd128")] {
242 Self { simd: v128_or(self.simd, rhs.simd) }
243 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
244 unsafe {Self { neon: vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
245 } else {
246 Self { arr: [
247 f64::from_bits(self.arr[0].to_bits() | rhs.arr[0].to_bits()),
248 f64::from_bits(self.arr[1].to_bits() | rhs.arr[1].to_bits()),
249 ]}
250 }
251 }
252 }
253
254 #[inline]
255 fn bitxor(self, rhs: Self) -> Self::Output {
256 pick! {
257 if #[cfg(target_feature="sse2")] {
258 Self { sse: bitxor_m128d(self.sse, rhs.sse) }
259 } else if #[cfg(target_feature="simd128")] {
260 Self { simd: v128_xor(self.simd, rhs.simd) }
261 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
262 unsafe {Self { neon: vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(self.neon), vreinterpretq_u64_f64(rhs.neon))) }}
263 } else {
264 Self { arr: [
265 f64::from_bits(self.arr[0].to_bits() ^ rhs.arr[0].to_bits()),
266 f64::from_bits(self.arr[1].to_bits() ^ rhs.arr[1].to_bits()),
267 ]}
268 }
269 }
270 }
271
272 #[inline]
273 fn simd_eq(self, rhs: Self) -> Self::Output {
274 pick! {
275 if #[cfg(target_feature="sse2")] {
276 Self { sse: cmp_eq_mask_m128d(self.sse, rhs.sse) }
277 } else if #[cfg(target_feature="simd128")] {
278 Self { simd: f64x2_eq(self.simd, rhs.simd) }
279 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
280 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, rhs.neon)) }}
281 } else {
282 Self { arr: [
283 if self.arr[0] == rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
284 if self.arr[1] == rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
285 ]}
286 }
287 }
288 }
289
290 #[inline]
291 fn simd_ne(self, rhs: Self) -> Self::Output {
292 pick! {
293 if #[cfg(target_feature="sse2")] {
294 Self { sse: cmp_neq_mask_m128d(self.sse, rhs.sse) }
295 } else if #[cfg(target_feature="simd128")] {
296 Self { simd: f64x2_ne(self.simd, rhs.simd) }
297 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
298 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, rhs.neon)) }.not() }
299 } else {
300 Self { arr: [
301 if self.arr[0] != rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
302 if self.arr[1] != rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
303 ]}
304 }
305 }
306 }
307
308 #[inline]
309 fn simd_lt(self, rhs: Self) -> Self::Output {
310 pick! {
311 if #[cfg(target_feature="sse2")] {
312 Self { sse: cmp_lt_mask_m128d(self.sse, rhs.sse) }
313 } else if #[cfg(target_feature="simd128")] {
314 Self { simd: f64x2_lt(self.simd, rhs.simd) }
315 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
316 unsafe {Self { neon: vreinterpretq_f64_u64(vcltq_f64(self.neon, rhs.neon)) }}
317 } else {
318 Self { arr: [
319 if self.arr[0] < rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
320 if self.arr[1] < rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
321 ]}
322 }
323 }
324 }
325
326 #[inline]
327 fn simd_gt(self, rhs: Self) -> Self::Output {
328 pick! {
329 if #[cfg(target_feature="avx")] {
330 Self { sse: cmp_op_mask_m128d::<{cmp_op!(GreaterThanOrdered)}>(self.sse, rhs.sse) }
331 } else if #[cfg(target_feature="sse2")] {
332 Self { sse: cmp_gt_mask_m128d(self.sse, rhs.sse) }
333 } else if #[cfg(target_feature="simd128")] {
334 Self { simd: f64x2_gt(self.simd, rhs.simd) }
335 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
336 unsafe {Self { neon: vreinterpretq_f64_u64(vcgtq_f64(self.neon, rhs.neon)) }}
337 } else {
338 Self { arr: [
339 if self.arr[0] > rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
340 if self.arr[1] > rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
341 ]}
342 }
343 }
344 }
345
346 #[inline]
347 fn simd_le(self, rhs: Self) -> Self::Output {
348 pick! {
349 if #[cfg(target_feature="sse2")] {
350 Self { sse: cmp_le_mask_m128d(self.sse, rhs.sse) }
351 } else if #[cfg(target_feature="simd128")] {
352 Self { simd: f64x2_le(self.simd, rhs.simd) }
353 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
354 unsafe {Self { neon: vreinterpretq_f64_u64(vcleq_f64(self.neon, rhs.neon)) }}
355 } else {
356 Self { arr: [
357 if self.arr[0] <= rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
358 if self.arr[1] <= rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
359 ]}
360 }
361 }
362 }
363
364 #[inline]
365 fn simd_ge(self, rhs: Self) -> Self::Output {
366 pick! {
367 if #[cfg(target_feature="sse2")] {
368 Self { sse: cmp_ge_mask_m128d(self.sse, rhs.sse) }
369 } else if #[cfg(target_feature="simd128")] {
370 Self { simd: f64x2_ge(self.simd, rhs.simd) }
371 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
372 unsafe {Self { neon: vreinterpretq_f64_u64(vcgeq_f64(self.neon, rhs.neon)) }}
373 } else {
374 Self { arr: [
375 if self.arr[0] >= rhs.arr[0] { f64::from_bits(u64::MAX) } else { 0.0 },
376 if self.arr[1] >= rhs.arr[1] { f64::from_bits(u64::MAX) } else { 0.0 },
377 ]}
378 }
379 }
380 }
381
382 #[inline]
383 pub fn reduce_add(self) -> f64 {
384 pick! {
385 if #[cfg(target_feature="ssse3")] {
386 let a = add_horizontal_m128d(self.sse, self.sse);
387 a.to_array()[0]
388 } else if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
389 let a: [f64;2] = cast(self);
390 a.iter().sum()
391 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
392 unsafe { vgetq_lane_f64(self.neon,0) + vgetq_lane_f64(self.neon,1) }
393 } else {
394 self.arr.iter().sum()
395 }
396 }
397 }
398
399 #[inline]
400 pub fn reduce_mul(self) -> f64 {
401 let arr: [f64; 2] = cast(self);
402 arr.iter().product()
403 }
404
405 #[inline]
406 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
407 pick! {
408 if #[cfg(target_feature="sse2")] {
409 Self {
410 sse: bitor_m128d(
411 bitand_m128d(if_one.sse, self.sse),
412 bitandnot_m128d(self.sse, if_zero.sse),
413 ),
414 }
415 } else if #[cfg(target_feature="simd128")] {
416 Self { simd: v128_bitselect(if_one.simd, if_zero.simd, self.simd) }
417 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
418 unsafe {Self { neon: vbslq_f64(vreinterpretq_u64_f64(self.neon), if_one.neon, if_zero.neon) }}
419 } else {
420 generic_bit_blend(self, if_one, if_zero)
421 }
422 }
423 }
424
425 #[inline]
426 fn select(self, if_true: Self, if_false: Self) -> Self {
427 pick! {
428 if #[cfg(target_feature="sse4.1")] {
429 Self { sse: blend_varying_m128d(if_false.sse, if_true.sse, self.sse) }
430 } else if #[cfg(target_feature="simd128")] {
431 Self { simd: v128_bitselect(if_true.simd, if_false.simd, self.simd) }
432 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
433 unsafe {Self { neon: vbslq_f64(vreinterpretq_u64_f64(self.neon), if_true.neon, if_false.neon) }}
434 } else {
435 generic_bit_blend(self, if_true, if_false)
436 }
437 }
438 }
439
440 #[inline]
441 pub fn to_bitmask(self) -> u32 {
442 pick! {
443 if #[cfg(target_feature="sse2")] {
444 move_mask_m128d(self.sse) as u32
445 } else if #[cfg(target_feature="simd128")] {
446 u64x2_bitmask(self.simd) as u32
447 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
448 unsafe
449 {
450 let e = vreinterpretq_u64_f64(self.neon);
451
452 (vgetq_lane_u64(e,0) >> 63 | ((vgetq_lane_u64(e,1) >> 62) & 0x2)) as u32
453 }
454 } else {
455 (((self.arr[0].to_bits() as i64) < 0) as u32) |
456 (((self.arr[1].to_bits() as i64) < 0) as u32) << 1
457 }
458 }
459 }
460
461 #[inline]
462 pub fn any(self) -> bool {
463 pick! {
464 if #[cfg(target_feature="simd128")] {
465 v128_any_true(self.simd)
466 } else {
467 self.to_bitmask() != 0
468 }
469 }
470 }
471
472 #[inline]
473 pub fn all(self) -> bool {
474 pick! {
475 if #[cfg(target_feature="simd128")] {
476 u64x2_all_true(self.simd)
477 } else {
478 self.to_bitmask() == 0b11
480 }
481 }
482 }
483
484 #[inline]
487 pub fn transpose(data: [f64x2; 2]) -> [f64x2; 2] {
488 pick! {
489 if #[cfg(any(
490 target_feature="sse2",
491 all(target_feature="neon",target_arch="aarch64"),
492 target_feature="simd128",
493 ))] {
494 [data[0].unpack_lo(data[1]), data[0].unpack_hi(data[1])]
495 } else {
496 let [x, y, z, w]: [f64; 4] = cast(data);
497 cast([x, z, y, w])
498 }
499 }
500 }
501
502 #[inline]
503 pub fn is_nan(self) -> Self {
504 pick! {
505 if #[cfg(target_feature="sse2")] {
506 Self { sse: cmp_unord_mask_m128d(self.sse, self.sse) }
507 } else if #[cfg(target_feature="simd128")] {
508 Self { simd: f64x2_ne(self.simd, self.simd) }
509 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
510 unsafe {Self { neon: vreinterpretq_f64_u64(vceqq_f64(self.neon, self.neon)) }.not() }
511 } else {
512 Self { arr: [
513 if self.arr[0].is_nan() { f64::from_bits(u64::MAX) } else { 0.0 },
514 if self.arr[1].is_nan() { f64::from_bits(u64::MAX) } else { 0.0 },
515 ]}
516 }
517 }
518 }
519
520 #[inline]
521 pub fn is_inf(self) -> Self {
522 let shifted_inf = u64x2::from(0xFFE0000000000000);
523 let u: u64x2 = cast(self);
524 let shift_u = u << 1_u64;
525 let out = (shift_u).simd_eq(shifted_inf);
526 cast(out)
527 }
528
529 #[inline]
530 pub fn is_finite(self) -> Self {
531 let shifted_exp_mask = u64x2::from(0xFFE0000000000000);
532 let u: u64x2 = cast(self);
533 let shift_u = u << 1_u64;
534 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
535 cast(out)
536 }
537
538 #[inline]
539 pub fn is_sign_positive(self) -> Self {
540 pick! {
541 if #[cfg(any(target_feature = "sse4.1", not(target_feature = "sse2")))] {
543 const SIGN_MASK: u64x2 = u64x2::splat((-0.0_f64).to_bits());
544
545 let bits = cast::<f64x2, u64x2>(self);
546 let sign = bits & SIGN_MASK;
547 let result = sign.simd_eq(u64x2::ZERO);
548 cast::<u64x2, f64x2>(result)
549 } else {
550 let bits = cast::<f64x2, u64x2>(self);
551 let sign = bits >> 63;
552 let sign = cast::<u64x2, f64x2>(sign);
553 sign.simd_eq(f64x2::ZERO)
554 }
555 }
556 }
557
558 #[inline]
559 pub fn is_sign_negative(self) -> Self {
560 pick! {
561 if #[cfg(any(target_feature = "sse4.1", not(target_feature = "sse2")))] {
563 const SIGN_MASK: u64x2 = u64x2::splat((-0.0_f64).to_bits());
564
565 let bits = cast::<f64x2, u64x2>(self);
566 let sign = bits & SIGN_MASK;
567 let result = sign.simd_eq(SIGN_MASK);
568 cast::<u64x2, f64x2>(result)
569 } else {
570 let bits = cast::<f64x2, u64x2>(self);
571 let sign = bits >> 63;
572 let sign = cast::<u64x2, f64x2>(sign);
573 sign.simd_ne(f64x2::ZERO)
574 }
575 }
576 }
577
578 #[inline]
579 pub fn recip(self) -> Self {
580 Self::ONE / self
583 }
584
585 #[inline]
586 pub fn recip_sqrt(self) -> Self {
587 Self::ONE / self.sqrt()
590 }
591
592 #[inline]
593 pub fn max(self, rhs: Self) -> Self {
594 pick! {
595 if #[cfg(target_feature="sse2")] {
596 rhs.is_nan().select(self, Self { sse: max_m128d(self.sse, rhs.sse) })
600 } else if #[cfg(target_feature="simd128")] {
601 Self {
608 simd: v128_bitselect(
609 rhs.simd,
610 f64x2_pmax(self.simd, rhs.simd),
611 f64x2_ne(self.simd, self.simd), )
613 }
614 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
615 unsafe {Self { neon: vmaxnmq_f64(self.neon, rhs.neon) }}
616 } else {
617 Self { arr: [
618 self.arr[0].max(rhs.arr[0]),
619 self.arr[1].max(rhs.arr[1]),
620 ]}
621 }
622 }
623 }
624
625 #[inline]
626 pub fn fast_max(self, rhs: Self) -> Self {
627 pick! {
628 if #[cfg(target_feature="sse2")] {
629 Self { sse: max_m128d(self.sse, rhs.sse) }
630 } else if #[cfg(target_feature="simd128")] {
631 Self {
632 simd: f64x2_pmax(self.simd, rhs.simd),
633 }
634 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
635 unsafe {Self { neon: vmaxq_f64(self.neon, rhs.neon) }}
636 } else {
637 Self { arr: [
638 if self.arr[0] < rhs.arr[0] { rhs.arr[0] } else { self.arr[0] },
639 if self.arr[1] < rhs.arr[1] { rhs.arr[1] } else { self.arr[1] },
640 ]}
641 }
642 }
643 }
644
645 #[inline]
646 pub fn min(self, rhs: Self) -> Self {
647 pick! {
648 if #[cfg(target_feature="sse2")] {
649 rhs.is_nan().select(self, Self { sse: min_m128d(self.sse, rhs.sse) })
653 } else if #[cfg(target_feature="simd128")] {
654 Self {
661 simd: v128_bitselect(
662 rhs.simd,
663 f64x2_pmin(self.simd, rhs.simd),
664 f64x2_ne(self.simd, self.simd), )
666 }
667 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
668 unsafe {Self { neon: vminnmq_f64(self.neon, rhs.neon) }}
669 } else {
670 Self { arr: [
671 self.arr[0].min(rhs.arr[0]),
672 self.arr[1].min(rhs.arr[1]),
673 ]}
674 }
675 }
676 }
677
678 #[inline]
679 pub fn fast_min(self, rhs: Self) -> Self {
680 pick! {
681 if #[cfg(target_feature="sse2")] {
682 Self { sse: min_m128d(self.sse, rhs.sse) }
683 } else if #[cfg(target_feature="simd128")] {
684 Self {
685 simd: f64x2_pmin(self.simd, rhs.simd),
686 }
687 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
688 unsafe {Self { neon: vminq_f64(self.neon, rhs.neon) }}
689 } else {
690 Self { arr: [
691 if self.arr[0] < rhs.arr[0] { self.arr[0] } else { rhs.arr[0] },
692 if self.arr[1] < rhs.arr[1] { self.arr[1] } else { rhs.arr[1] },
693 ]}
694 }
695 }
696 }
697
698 #[inline]
699 pub fn clamp(self, min: Self, max: Self) -> Self {
700 pick! {
701 if #[cfg(any(
702 target_feature="simd128",
703 all(target_feature="neon",target_arch="aarch64"),
704 ))] {
705 self.fast_clamp(min, max)
707 } else {
708 self.fast_clamp(min, max) | min.is_nan() | max.is_nan()
710 }
711 }
712 }
713
714 #[inline]
715 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
716 pick! {
717 if #[cfg(target_feature="sse2")] {
718 Self { sse: max_m128d(min.sse, min_m128d(max.sse, self.sse)) }
721 } else if #[cfg(target_feature="simd128")] {
722 Self { simd: f64x2_max(f64x2_min(self.simd, max.simd), min.simd) }
723 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
724 unsafe { Self { neon: vmaxq_f64(vminq_f64(self.neon, max.neon), min.neon) } }
725 } else {
726 let mut result = self;
729 result = result.simd_gt(max).select(max, result);
730 result = result.simd_lt(min).select(min, result);
731 result
732 }
733 }
734 }
735
736 #[inline]
737 pub fn abs(self) -> Self {
738 pick! {
739 if #[cfg(target_feature="simd128")] {
740 Self { simd: f64x2_abs(self.simd) }
741 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
742 unsafe {Self { neon: vabsq_f64(self.neon) }}
743 } else {
744 let non_sign_bits = f64x2::from(f64::from_bits(i64::MAX as u64));
745 self & non_sign_bits
746 }
747 }
748 }
749
750 #[inline]
751 pub fn floor(self) -> Self {
752 pick! {
753 if #[cfg(target_feature="simd128")] {
754 Self { simd: f64x2_floor(self.simd) }
755 } else if #[cfg(target_feature="sse4.1")] {
756 Self { sse: floor_m128d(self.sse) }
757 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
758 unsafe {Self { neon: vrndmq_f64(self.neon) }}
759 } else if #[cfg(feature="std")] {
760 let base: [f64; 2] = cast(self);
761 cast(base.map(|val| val.floor()))
762 } else {
763 let base: [f64; 2] = cast(self);
764 let rounded: [f64; 2] = cast(self.round());
765 cast([
766 if base[0] < rounded[0] { rounded[0] - 1.0 } else { rounded[0] },
767 if base[1] < rounded[1] { rounded[1] - 1.0 } else { rounded[1] },
768 ])
769 }
770 }
771 }
772
773 #[inline]
774 pub fn ceil(self) -> Self {
775 pick! {
776 if #[cfg(target_feature="simd128")] {
777 Self { simd: f64x2_ceil(self.simd) }
778 } else if #[cfg(target_feature="sse4.1")] {
779 Self { sse: ceil_m128d(self.sse) }
780 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
781 unsafe {Self { neon: vrndpq_f64(self.neon) }}
782 } else if #[cfg(feature="std")] {
783 let base: [f64; 2] = cast(self);
784 cast(base.map(|val| val.ceil()))
785 } else {
786 let base: [f64; 2] = cast(self);
787 let rounded: [f64; 2] = cast(self.round());
788 cast([
789 if base[0] > rounded[0] { rounded[0] + 1.0 } else { rounded[0] },
790 if base[1] > rounded[1] { rounded[1] + 1.0 } else { rounded[1] },
791 ])
792 }
793 }
794 }
795
796 #[inline]
797 pub fn round(self) -> Self {
798 pick! {
799 if #[cfg(target_feature="sse4.2")] {
800 const_f64_as_f64x2!(HALF_NEXT_DOWN, 0.5_f64.next_down());
801 const_f64_as_f64x2!(BOUNDS_LIMIT, 4503599627370496.0);
802
803 let self_abs = self.abs();
804
805 let adjusted_self = self_abs + Self::HALF;
806 let result_abs = Self { sse: round_m128d::<{round_op!(Zero)}>(adjusted_self.sse) };
807 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
810
811 let bounds_mask: Self = cast(cmp_gt_mask_i64_m128i(cast(BOUNDS_LIMIT), cast(self_abs)));
813
814 bounds_mask.abs().bitselect(result_abs, self)
816 } else if #[cfg(target_feature="simd128")] {
817 const_f64_as_f64x2!(HALF_NEXT_DOWN, 0.5_f64.next_down());
818 const_f64_as_f64x2!(BOUNDS_LIMIT, 4503599627370496.0);
819
820 let self_abs = self.abs();
821
822 let adjusted_self = self_abs + Self::HALF;
823 let result_abs = Self { simd: f64x2_trunc(adjusted_self.simd) };
824 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
827
828 let bounds_mask = Self { simd: i64x2_lt(self_abs.simd, BOUNDS_LIMIT.simd) };
830
831 bounds_mask.abs().bitselect(result_abs, self)
833 } else {
834 const_f64_as_f64x2!(HALF_NEXT_DOWN, 0.5_f64.next_down());
835 const_f64_as_f64x2!(BOUNDS_LIMIT, 4503599627370496.0);
836
837 let self_abs = self.abs();
838
839 let adjusted_self = (self_abs + Self::HALF).to_array();
840 let result_abs = Self::new([
841 adjusted_self[0] as u64 as f64,
842 adjusted_self[1] as u64 as f64,
843 ]);
844 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
847
848 let bounds_mask: Self = cast(cast::<_, i64x2>(self_abs).simd_lt(cast::<_, i64x2>(BOUNDS_LIMIT)));
850
851 bounds_mask.abs().bitselect(result_abs, self)
853 }
854 }
855 }
856
857 #[inline]
858 pub fn round_int(self) -> i64x2 {
859 pick! {
860 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
861 #[cfg(target_arch = "x86")]
862 use core::arch::x86::_mm_cvtpd_epi64;
863 #[cfg(target_arch = "x86_64")]
864 use core::arch::x86_64::_mm_cvtpd_epi64;
865
866 let non_nan_mask = self.simd_eq(self);
868 let non_nan = self & non_nan_mask;
869 let flip_to_max: i64x2 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
870
871 let cast: i64x2 = cast(m128i(unsafe { _mm_cvtpd_epi64(non_nan.sse.0) }));
873 flip_to_max ^ cast
874 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
875 cast(Self { neon: unsafe { vreinterpretq_f64_s64(vcvtnq_s64_f64(self.neon)) } })
876 } else {
877 let rounded: [f64; 2] = cast(self.round_ties_even());
878 cast([rounded[0] as i64, rounded[1] as i64])
879 }
880 }
881 }
882
883 #[inline]
884 pub fn fast_round_int(self) -> i64x2 {
885 pick! {
886 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
887 #[cfg(target_arch = "x86")]
888 use core::arch::x86::_mm_cvtpd_epi64;
889 #[cfg(target_arch = "x86_64")]
890 use core::arch::x86_64::_mm_cvtpd_epi64;
891
892 cast(m128i(unsafe { _mm_cvtpd_epi64(self.sse.0) }))
894 } else {
895 self.round_int()
896 }
897 }
898 }
899
900 #[inline]
901 pub fn round_ties_even(self) -> Self {
902 pick! {
903 if #[cfg(target_feature="sse4.1")] {
904 Self { sse: round_m128d::<{round_op!(Nearest)}>(self.sse) }
905 } else if #[cfg(target_feature="simd128")] {
906 Self { simd: f64x2_nearest(self.simd) }
907 } else {
908 const SIGN_MASK: f64x2 = f64x2::splat(-0.0);
909 const MAGIC_VALUE: f64x2 = f64x2::splat(f64::from_bits(0x43300000_00000000));
910
911 let self_sign = self & SIGN_MASK;
912 let magic_value = MAGIC_VALUE | self_sign;
913 let result = self + magic_value - magic_value;
914
915 let bounds_mask = self.abs().simd_le(MAGIC_VALUE);
916 bounds_mask.abs().select(result, self)
917 }
918 }
919 }
920
921 #[inline]
922 pub fn trunc(self) -> Self {
923 pick! {
924 if #[cfg(target_feature="sse4.1")] {
925 Self { sse: round_m128d::<{round_op!(Zero)}>(self.sse) }
926 } else if #[cfg(target_feature="simd128")] {
927 Self { simd: f64x2_trunc(self.simd) }
928 } else {
929 let array: [f64; 2] = cast(self);
934 let result: Self = cast([
935 array[0] as i64 as f64,
936 array[1] as i64 as f64,
937 ]);
938
939 const BOUNDS_LIMIT: i64 = 18e15_f64.to_bits().cast_signed();
942 let bounds_mask: Self = cast(cast::<f64x2, i64x2>(self.abs()).simd_lt(i64x2::splat(BOUNDS_LIMIT)));
943
944 bounds_mask.abs().select(result, self)
946 }
947 }
948 }
949
950 #[inline]
951 pub fn trunc_int(self) -> i64x2 {
952 pick! {
953 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
954 #[cfg(target_arch = "x86")]
955 use core::arch::x86::_mm_cvttpd_epi64;
956 #[cfg(target_arch = "x86_64")]
957 use core::arch::x86_64::_mm_cvttpd_epi64;
958
959 let non_nan_mask = self.simd_eq(self);
961 let non_nan = self & non_nan_mask;
962 let flip_to_max: i64x2 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
963
964 let cast: i64x2 = cast(m128i(unsafe { _mm_cvttpd_epi64(non_nan.sse.0) }));
966 flip_to_max ^ cast
967 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
968 cast(Self { neon: unsafe { vreinterpretq_f64_s64(vcvtq_s64_f64(self.neon)) } })
969 } else {
970 let n: [f64;2] = cast(self);
972 cast([n[0] as i64, n[1] as i64])
973 }
974 }
975 }
976
977 #[inline]
978 pub fn fast_trunc_int(self) -> i64x2 {
979 pick! {
980 if #[cfg(all(target_feature="avx512dq", target_feature="avx512vl"))] {
981 #[cfg(target_arch = "x86")]
982 use core::arch::x86::_mm_cvttpd_epi64;
983 #[cfg(target_arch = "x86_64")]
984 use core::arch::x86_64::_mm_cvttpd_epi64;
985
986 cast(m128i(unsafe { _mm_cvttpd_epi64(self.sse.0) }))
988 } else {
989 self.trunc_int()
990 }
991 }
992 }
993
994 #[inline]
1002 pub fn mul_add(self, a: Self, b: Self) -> Self {
1003 pick! {
1004 if #[cfg(all(target_feature="fma"))] {
1005 Self { sse: fused_mul_add_m128d(self.sse, a.sse, b.sse) }
1006 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1007 unsafe { Self { neon: vfmaq_f64(b.neon, self.neon, a.neon) } }
1008 } else {
1009 (self * a) + b
1010 }
1011 }
1012 }
1013
1014 #[inline]
1023 pub fn mul_sub(self, a: Self, b: Self) -> Self {
1024 pick! {
1025 if #[cfg(all(target_feature="fma"))] {
1026 Self { sse: fused_mul_sub_m128d(self.sse, a.sse, b.sse) }
1027 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1028 unsafe { Self { neon: vfmaq_f64(vnegq_f64(b.neon), self.neon, a.neon) } }
1029 } else {
1030 (self * a) - b
1031 }
1032 }
1033 }
1034
1035 #[inline]
1043 pub fn mul_neg_add(self, a: Self, b: Self) -> Self {
1044 pick! {
1045 if #[cfg(all(target_feature="fma"))] {
1046 Self { sse: fused_mul_neg_add_m128d(self.sse, a.sse, b.sse) }
1047 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1048 unsafe { Self { neon: vfmsq_f64(b.neon, self.neon, a.neon) } }
1049 } else {
1050 b - (self * a)
1051 }
1052 }
1053 }
1054
1055 #[inline]
1064 pub fn mul_neg_sub(self, a: Self, b: Self) -> Self {
1065 pick! {
1066 if #[cfg(all(target_feature="fma"))] {
1067 Self { sse: fused_mul_neg_sub_m128d(self.sse, a.sse, b.sse) }
1068 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1069 unsafe { Self { neon: vnegq_f64(vfmaq_f64(b.neon, self.neon, a.neon)) } }
1070 } else {
1071 -(self * a) - b
1072 }
1073 }
1074 }
1075
1076 #[inline]
1077 pub fn powf_simd(self, n: Self) -> Self {
1078 const_f64_as_f64x2!(ln2d_hi, 0.693145751953125);
1079 const_f64_as_f64x2!(ln2d_lo, 1.42860682030941723212E-6);
1080 const_f64_as_f64x2!(P0log, 2.0039553499201281259648E1);
1081 const_f64_as_f64x2!(P1log, 5.7112963590585538103336E1);
1082 const_f64_as_f64x2!(P2log, 6.0949667980987787057556E1);
1083 const_f64_as_f64x2!(P3log, 2.9911919328553073277375E1);
1084 const_f64_as_f64x2!(P4log, 6.5787325942061044846969E0);
1085 const_f64_as_f64x2!(P5log, 4.9854102823193375972212E-1);
1086 const_f64_as_f64x2!(P6log, 4.5270000862445199635215E-5);
1087 const_f64_as_f64x2!(Q0log, 6.0118660497603843919306E1);
1088 const_f64_as_f64x2!(Q1log, 2.1642788614495947685003E2);
1089 const_f64_as_f64x2!(Q2log, 3.0909872225312059774938E2);
1090 const_f64_as_f64x2!(Q3log, 2.2176239823732856465394E2);
1091 const_f64_as_f64x2!(Q4log, 8.3047565967967209469434E1);
1092 const_f64_as_f64x2!(Q5log, 1.5062909083469192043167E1);
1093
1094 const_f64_as_f64x2!(p2, 1.0 / 2.0); const_f64_as_f64x2!(p3, 1.0 / 6.0);
1097 const_f64_as_f64x2!(p4, 1.0 / 24.0);
1098 const_f64_as_f64x2!(p5, 1.0 / 120.0);
1099 const_f64_as_f64x2!(p6, 1.0 / 720.0);
1100 const_f64_as_f64x2!(p7, 1.0 / 5040.0);
1101 const_f64_as_f64x2!(p8, 1.0 / 40320.0);
1102 const_f64_as_f64x2!(p9, 1.0 / 362880.0);
1103 const_f64_as_f64x2!(p10, 1.0 / 3628800.0);
1104 const_f64_as_f64x2!(p11, 1.0 / 39916800.0);
1105 const_f64_as_f64x2!(p12, 1.0 / 479001600.0);
1106 const_f64_as_f64x2!(p13, 1.0 / 6227020800.0);
1107
1108 let x1 = self.abs();
1109 let x = x1.fraction_2();
1110 let mask = x.simd_gt(f64x2::SQRT_2 * f64x2::HALF);
1111 let x = (!mask).select(x + x, x);
1112 let x = x - f64x2::ONE;
1113 let x2 = x * x;
1114 let px = polynomial_6!(x, P0log, P1log, P2log, P3log, P4log, P5log, P6log);
1115 let px = px * x * x2;
1116 let qx = polynomial_6n!(x, Q0log, Q1log, Q2log, Q3log, Q4log, Q5log);
1117 let lg1 = px / qx;
1118
1119 let ef = x1.exponent();
1120 let ef = mask.select(ef + f64x2::ONE, ef);
1121 let e1 = (ef * n).round_ties_even();
1122 let yr = ef.mul_sub(n, e1);
1123
1124 let lg = f64x2::HALF.mul_neg_add(x2, x) + lg1;
1125 let x2err = (f64x2::HALF * x).mul_sub(x, f64x2::HALF * x2);
1126 let lg_err = f64x2::HALF.mul_add(x2, lg - x) - lg1;
1127
1128 let e2 = (lg * n * f64x2::LOG2_E).round_ties_even();
1129 let v = lg.mul_sub(n, e2 * ln2d_hi);
1130 let v = e2.mul_neg_add(ln2d_lo, v);
1131 let v = v - (lg_err + x2err).mul_sub(n, yr * f64x2::LN_2);
1132
1133 let x = v;
1134 let e3 = (x * f64x2::LOG2_E).round_ties_even();
1135 let x = e3.mul_neg_add(f64x2::LN_2, x);
1136 let z =
1137 polynomial_13!(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)
1138 + f64x2::ONE;
1139 let ee = e1 + e2 + e3;
1140 let ei = cast::<_, i64x2>(ee.round_int());
1141 let ej = cast::<_, i64x2>(ei + (cast::<_, i64x2>(z) >> 52));
1142
1143 let overflow = cast::<_, f64x2>(!ej.simd_lt(i64x2::splat(0x07FF)))
1144 | ee.simd_gt(f64x2::splat(3000.0));
1145 let underflow = cast::<_, f64x2>(!ej.simd_gt(i64x2::splat(0x000)))
1146 | ee.simd_lt(f64x2::splat(-3000.0));
1147
1148 let z = cast::<_, f64x2>(cast::<_, i64x2>(z) + (ei << 52));
1150
1151 let z = if (overflow | underflow).any() {
1153 let z = underflow.select(f64x2::ZERO, z);
1154 overflow.select(Self::infinity(), z)
1155 } else {
1156 z
1157 };
1158
1159 let x_zero = self.is_zero_or_subnormal();
1161 let z = x_zero.select(
1162 n.simd_lt(f64x2::ZERO).select(
1163 Self::infinity(),
1164 n.simd_eq(f64x2::ZERO).select(f64x2::ONE, f64x2::ZERO),
1165 ),
1166 z,
1167 );
1168
1169 let x_sign = self.is_sign_negative();
1170 let z = if x_sign.any() {
1171 let yi = n.simd_eq(n.round_ties_even());
1173 let y_odd = cast::<i64x2, f64x2>(n.round_int() << 63);
1175
1176 let z1 = yi
1177 .select(z | y_odd, self.simd_eq(Self::ZERO).select(z, Self::nan_pow()));
1178 x_sign.select(z1, z)
1179 } else {
1180 z
1181 };
1182
1183 let x_finite = self.is_finite();
1184 let y_finite = n.is_finite();
1185 let e_finite = ee.is_finite();
1186
1187 if (x_finite & y_finite & (e_finite | x_zero)).all() {
1188 return z;
1189 }
1190
1191 (self.is_nan() | n.is_nan()).select(self + n, z)
1192 }
1193
1194 #[inline]
1195 pub fn sqrt(self) -> Self {
1196 pick! {
1197 if #[cfg(target_feature="sse2")] {
1198 Self { sse: sqrt_m128d(self.sse) }
1199 } else if #[cfg(target_feature="simd128")] {
1200 Self { simd: f64x2_sqrt(self.simd) }
1201 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1202 unsafe {Self { neon: vsqrtq_f64(self.neon) }}
1203 } else if #[cfg(feature="std")] {
1204 Self { arr: [
1205 self.arr[0].sqrt(),
1206 self.arr[1].sqrt(),
1207 ]}
1208 } else {
1209 Self { arr: [
1210 software_sqrt(self.arr[0]),
1211 software_sqrt(self.arr[1]),
1212 ]}
1213 }
1214 }
1215 }
1216
1217 #[inline]
1219 pub fn exp(self) -> Self {
1220 const_f64_as_f64x2!(P2, 1.0 / 2.0);
1221 const_f64_as_f64x2!(P3, 1.0 / 6.0);
1222 const_f64_as_f64x2!(P4, 1.0 / 24.0);
1223 const_f64_as_f64x2!(P5, 1.0 / 120.0);
1224 const_f64_as_f64x2!(P6, 1.0 / 720.0);
1225 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
1226 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
1227 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
1228 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
1229 const_f64_as_f64x2!(P11, 1.0 / 39916800.0);
1230 const_f64_as_f64x2!(P12, 1.0 / 479001600.0);
1231 const_f64_as_f64x2!(P13, 1.0 / 6227020800.0);
1232 const_f64_as_f64x2!(LN2D_HI, 0.693145751953125);
1236 const_f64_as_f64x2!(LN2D_LO, 1.42860682030941723212E-6);
1237 let max_x = f64x2::from(709.783);
1238 let min_x = f64x2::from(-744.79);
1239 let finite = self.is_finite();
1240 let neg_underflow = self.simd_lt(min_x) & finite;
1242 if neg_underflow.all() {
1243 return Self::ZERO;
1244 }
1245 let max_r = f64x2::from(1023.0);
1246 let r = (self * Self::LOG2_E).round_ties_even();
1247 let big = r.simd_gt(max_r);
1248 let r_safe = big.select(max_r, r);
1249 let excess = r - max_r;
1250 let excess = big.select(excess, Self::ZERO);
1251 let scale = Self::vm_pow2n(excess);
1252 let x = r.mul_neg_add(LN2D_HI, self);
1253 let x = r.mul_neg_add(LN2D_LO, x);
1254 let z =
1255 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1256 let n2 = Self::vm_pow2n(r_safe);
1257 let z = (z + Self::ONE) * scale * n2;
1258 let nan_mask = self.is_nan();
1259 let mut result = nan_mask.select(Self::nan_pow(), z);
1260 let pos_overflow = self.simd_gt(max_x) & finite;
1261 result = pos_overflow.select(Self::infinity(), result);
1262 result = neg_underflow.select(Self::ZERO, result);
1263 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1264 result = pos_inf.select(Self::infinity(), result);
1265 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1266 result = neg_inf.select(Self::ZERO, result);
1267 result
1268 }
1269
1270 #[inline]
1271 pub fn exp2(self) -> Self {
1272 const_f64_as_f64x2!(P2, 1.0 / 2.0);
1273 const_f64_as_f64x2!(P3, 1.0 / 6.0);
1274 const_f64_as_f64x2!(P4, 1.0 / 24.0);
1275 const_f64_as_f64x2!(P5, 1.0 / 120.0);
1276 const_f64_as_f64x2!(P6, 1.0 / 720.0);
1277 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
1278 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
1279 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
1280 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
1281
1282 let max_x = f64x2::from(1023.9999999999999);
1285 let min_x = f64x2::from(-1074.5);
1286 let finite = self.is_finite();
1287 let neg_underflow = self.simd_lt(min_x) & finite;
1288 if neg_underflow.all() {
1289 return Self::ZERO;
1290 }
1291
1292 let round = self.round_ties_even();
1293 let max_r = f64x2::from(1023.0);
1294 let big = round.simd_gt(max_r);
1295 let r_safe = big.select(max_r, round);
1296 let excess = round - max_r;
1297 let excess = big.select(excess, Self::ZERO);
1298 let scale = Self::vm_pow2n(excess);
1299
1300 let fract = (self - round) * Self::LN_2;
1301 let fract_partial_exp2 =
1302 polynomial_8!(fract, P2, P3, P4, P5, P6, P7, P8, P9, P10);
1303 let fract2 = fract * fract;
1304 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1305
1306 let n2 = Self::vm_pow2n(r_safe);
1307 let result = fract_exp2 * scale * n2;
1308
1309 let nan_mask = self.is_nan();
1310 let mut result = nan_mask.select(Self::nan_pow(), result);
1311 let pos_overflow = self.simd_gt(max_x) & finite;
1312 result = pos_overflow.select(Self::infinity(), result);
1313 result = neg_underflow.select(Self::ZERO, result);
1314 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1315 result = pos_inf.select(Self::infinity(), result);
1316 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1317 result = neg_inf.select(Self::ZERO, result);
1318 result
1319 }
1320
1321 #[inline]
1322 pub fn ln(self) -> Self {
1323 const_f64_as_f64x2!(P0, 7.70838733755885391666E0);
1324 const_f64_as_f64x2!(P1, 1.79368678507819816313E1);
1325 const_f64_as_f64x2!(P2, 1.44989225341610930846E1);
1326 const_f64_as_f64x2!(P3, 4.70579119878881725854E0);
1327 const_f64_as_f64x2!(P4, 4.97494994976747001425E-1);
1328 const_f64_as_f64x2!(P5, 1.01875663804580931796E-4);
1329
1330 const_f64_as_f64x2!(Q0, 2.31251620126765340583E1);
1331 const_f64_as_f64x2!(Q1, 7.11544750618563894466E1);
1332 const_f64_as_f64x2!(Q2, 8.29875266912776603211E1);
1333 const_f64_as_f64x2!(Q3, 4.52279145837532221105E1);
1334 const_f64_as_f64x2!(Q4, 1.12873587189167450590E1);
1335 const_f64_as_f64x2!(LN2F_HI, f64::from_bits(0x3FE62E42FEE00000));
1341 const_f64_as_f64x2!(LN2F_LO, f64::from_bits(0x3DEA39EF35793C76));
1342 const_f64_as_f64x2!(VM_SQRT2, 1.414213562373095048801);
1343 const_f64_as_f64x2!(VM_SMALLEST_NORMAL, 2.2250738585072014E-308);
1344
1345 let x1 = self;
1346 let x = Self::fraction_2(x1);
1347 let e = Self::exponent(x1);
1348 let mask = x.simd_gt(VM_SQRT2 * f64x2::HALF);
1349 let x = (!mask).select(x + x, x);
1350 let fe = mask.select(e + Self::ONE, e);
1351 let x = x - Self::ONE;
1352 let px = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1353 let x2 = x * x;
1354 let px = x2 * x * px;
1355 let qx = polynomial_5n!(x, Q0, Q1, Q2, Q3, Q4);
1356 let res = px / qx;
1357 let res = fe.mul_add(LN2F_LO, res);
1358 let res = res + x2.mul_neg_add(f64x2::HALF, x);
1359 let res = fe.mul_add(LN2F_HI, res);
1360 let overflow = !self.is_finite();
1361 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1362 let mask = overflow | underflow;
1363 if !mask.any() {
1364 res
1365 } else {
1366 let is_zero = self.is_zero_or_subnormal();
1367 let res = underflow.select(Self::nan_log(), res);
1368 let res = is_zero.select(-Self::infinity(), res);
1373 let res = overflow.select(self, res);
1374 let res = (!self.is_finite() & self.is_sign_negative())
1376 .select(Self::nan_log(), res);
1377 res
1378 }
1379 }
1380
1381 #[inline]
1382 pub fn cbrt(self) -> Self {
1383 let a = self.abs();
1384 let zero = a.simd_eq(Self::ZERO);
1385 if zero.all() {
1386 return self; }
1388 let inf = a.is_inf();
1389 let nan = self.is_nan();
1390
1391 const SUBN_SCALE: f64 = 1.8014398509481984e16;
1392 const SUBN_CBRT: f64 = 262144.0;
1393 let tiny = a.simd_lt(Self::from(f64::MIN_POSITIVE));
1394 let a = tiny.select(a * Self::from(SUBN_SCALE), a);
1395
1396 let e = Self::exponent(a) + Self::ONE;
1397 let d = Self::fraction_2(a);
1398
1399 const_f64_as_f64x2!(C0, 2.2307275302496609725722);
1404 const_f64_as_f64x2!(C1, -3.85841935510444988821632);
1405 const_f64_as_f64x2!(C2, 6.03990368989458747961407);
1406 const_f64_as_f64x2!(C3, -5.73353060922947843636166);
1407 const_f64_as_f64x2!(C4, 2.96155103020039511818595);
1408 const_f64_as_f64x2!(C5, -0.640245898480692909870982);
1409 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1410
1411 let x2 = x * x;
1413 let x4 = x2 * x2;
1414 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1415
1416 let mut y = (d * x) * x;
1418 let yx = y * x;
1419 let t = Self::from(2.0 / 3.0);
1420 y = y - t * y * (yx - Self::ONE);
1421
1422 let three = Self::from(3.0);
1424 let two = Self::from(2.0);
1425 let neg = e.simd_lt(Self::ZERO);
1426 let e_adj = neg.select(e - two, e);
1427 let k = (e_adj / three).trunc();
1428 let r = e - three * k;
1429 const_f64_as_f64x2!(CBRT2, 1.2599210498948732);
1430 const_f64_as_f64x2!(CBRT4, 1.5874010519681994);
1431 y = r.simd_eq(Self::ONE).select(y * CBRT2, y);
1432 y = r.simd_eq(two).select(y * CBRT4, y);
1433 y *= Self::vm_pow2n(k);
1434 y = tiny.select(y / Self::from(SUBN_CBRT), y);
1435
1436 let result = y.flip_signs(self);
1437 let result = nan.select(self, result);
1438 let result = zero.select(self, result);
1439 let result = inf.select(self, result);
1440 result
1441 }
1442
1443 #[inline]
1444 pub fn asin(self) -> Self {
1445 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1448 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1449 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1450 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1451 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1452
1453 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1454 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1455 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1456 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1457
1458 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1459 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1460 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1461 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1462 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1463 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1464
1465 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1466 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1467 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1468 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1469 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1470
1471 let xa = self.abs();
1472
1473 let big = xa.simd_ge(f64x2::splat(0.625));
1474
1475 let x1 = big.select(f64x2::splat(1.0) - xa, xa * xa);
1476
1477 let x2 = x1 * x1;
1478 let x3 = x2 * x1;
1479 let x4 = x2 * x2;
1480 let x5 = x4 * x1;
1481
1482 let do_big = big.any();
1483 let do_small = !big.all();
1484
1485 let mut rx = f64x2::default();
1486 let mut sx = f64x2::default();
1487 let mut px = f64x2::default();
1488 let mut qx = f64x2::default();
1489
1490 if do_big {
1491 rx = x3.mul_add(R3asin, x2 * R2asin)
1492 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1493 sx =
1494 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1495 }
1496 if do_small {
1497 px = x3.mul_add(P3asin, P0asin)
1498 + x4.mul_add(P4asin, x1 * P1asin)
1499 + x5.mul_add(P5asin, x2 * P2asin);
1500 qx = x4.mul_add(Q4asin, x5)
1501 + x3.mul_add(Q3asin, x1 * Q1asin)
1502 + x2.mul_add(Q2asin, Q0asin);
1503 };
1504
1505 let vx = big.select(rx, px);
1506 let wx = big.select(sx, qx);
1507
1508 let y1 = vx / wx * x1;
1509
1510 let mut z1 = f64x2::default();
1511 let mut z2 = f64x2::default();
1512 if do_big {
1513 let xb = (x1 + x1).sqrt();
1514 z1 = xb.mul_add(y1, xb);
1515 }
1516
1517 if do_small {
1518 z2 = xa.mul_add(y1, xa);
1519 }
1520
1521 let z3 = f64x2::FRAC_PI_2 - z1;
1523 let asin = big.select(z3, z2);
1524 let asin = asin.flip_signs(self);
1525
1526 asin
1527 }
1528
1529 #[inline]
1530 pub fn acos(self) -> Self {
1531 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1534 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1535 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1536 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1537 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1538
1539 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1540 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1541 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1542 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1543
1544 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1545 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1546 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1547 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1548 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1549 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1550
1551 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1552 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1553 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1554 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1555 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1556
1557 let xa = self.abs();
1558
1559 let big = xa.simd_ge(f64x2::splat(0.625));
1560
1561 let x1 = big.select(f64x2::splat(1.0) - xa, xa * xa);
1562
1563 let x2 = x1 * x1;
1564 let x3 = x2 * x1;
1565 let x4 = x2 * x2;
1566 let x5 = x4 * x1;
1567
1568 let do_big = big.any();
1569 let do_small = !big.all();
1570
1571 let mut rx = f64x2::default();
1572 let mut sx = f64x2::default();
1573 let mut px = f64x2::default();
1574 let mut qx = f64x2::default();
1575
1576 if do_big {
1577 rx = x3.mul_add(R3asin, x2 * R2asin)
1578 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1579 sx =
1580 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1581 }
1582 if do_small {
1583 px = x3.mul_add(P3asin, P0asin)
1584 + x4.mul_add(P4asin, x1 * P1asin)
1585 + x5.mul_add(P5asin, x2 * P2asin);
1586 qx = x4.mul_add(Q4asin, x5)
1587 + x3.mul_add(Q3asin, x1 * Q1asin)
1588 + x2.mul_add(Q2asin, Q0asin);
1589 };
1590
1591 let vx = big.select(rx, px);
1592 let wx = big.select(sx, qx);
1593
1594 let y1 = vx / wx * x1;
1595
1596 let mut z1 = f64x2::default();
1597 let mut z2 = f64x2::default();
1598 if do_big {
1599 let xb = (x1 + x1).sqrt();
1600 z1 = xb.mul_add(y1, xb);
1601 }
1602
1603 if do_small {
1604 z2 = xa.mul_add(y1, xa);
1605 }
1606
1607 let z3 = self.simd_lt(f64x2::ZERO).select(f64x2::PI - z1, z1);
1609 let z4 = f64x2::FRAC_PI_2 - z2.flip_signs(self);
1610 let acos = big.select(z3, z4);
1611
1612 acos
1613 }
1614
1615 #[inline]
1616 pub fn atan(self) -> Self {
1617 const_f64_as_f64x2!(MORE_BITS, 6.123233995736765886130E-17);
1620 const_f64_as_f64x2!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1621 const_f64_as_f64x2!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1622
1623 const_f64_as_f64x2!(P4atan, -8.750608600031904122785E-1);
1624 const_f64_as_f64x2!(P3atan, -1.615753718733365076637E1);
1625 const_f64_as_f64x2!(P2atan, -7.500855792314704667340E1);
1626 const_f64_as_f64x2!(P1atan, -1.228866684490136173410E2);
1627 const_f64_as_f64x2!(P0atan, -6.485021904942025371773E1);
1628
1629 const_f64_as_f64x2!(Q4atan, 2.485846490142306297962E1);
1630 const_f64_as_f64x2!(Q3atan, 1.650270098316988542046E2);
1631 const_f64_as_f64x2!(Q2atan, 4.328810604912902668951E2);
1632 const_f64_as_f64x2!(Q1atan, 4.853903996359136964868E2);
1633 const_f64_as_f64x2!(Q0atan, 1.945506571482613964425E2);
1634
1635 let t = self.abs();
1636
1637 let notbig = t.simd_le(T3PO8);
1641 let notsmal = t.simd_ge(Self::splat(0.66));
1642
1643 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1644 s = notsmal & s;
1645 let mut fac = notbig.select(MORE_BITS_O2, MORE_BITS);
1646 fac = notsmal & fac;
1647
1648 let mut a = notbig & t;
1652 a = notsmal.select(a - Self::ONE, a);
1653 let mut b = notbig & Self::ONE;
1654 b = notsmal.select(b + t, b);
1655 let z = a / b;
1656
1657 let zz = z * z;
1658
1659 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1660 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1661
1662 let mut re = (px / qx).mul_add(z * zz, z);
1663 re += s + fac;
1664
1665 re = (self.is_sign_negative()).select(-re, re);
1667
1668 re
1669 }
1670
1671 #[inline]
1672 pub fn atan2(self, x: Self) -> Self {
1673 const_f64_as_f64x2!(MORE_BITS, 6.123233995736765886130E-17);
1676 const_f64_as_f64x2!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1677 const_f64_as_f64x2!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1678
1679 const_f64_as_f64x2!(P4atan, -8.750608600031904122785E-1);
1680 const_f64_as_f64x2!(P3atan, -1.615753718733365076637E1);
1681 const_f64_as_f64x2!(P2atan, -7.500855792314704667340E1);
1682 const_f64_as_f64x2!(P1atan, -1.228866684490136173410E2);
1683 const_f64_as_f64x2!(P0atan, -6.485021904942025371773E1);
1684
1685 const_f64_as_f64x2!(Q4atan, 2.485846490142306297962E1);
1686 const_f64_as_f64x2!(Q3atan, 1.650270098316988542046E2);
1687 const_f64_as_f64x2!(Q2atan, 4.328810604912902668951E2);
1688 const_f64_as_f64x2!(Q1atan, 4.853903996359136964868E2);
1689 const_f64_as_f64x2!(Q0atan, 1.945506571482613964425E2);
1690
1691 let y = self;
1692
1693 let x1 = x.abs();
1695 let y1 = y.abs();
1696 let swapxy = y1.simd_gt(x1);
1697 let mut x2 = swapxy.select(y1, x1);
1699 let mut y2 = swapxy.select(x1, y1);
1700
1701 let both_infinite = x.is_inf() & y.is_inf();
1703 if both_infinite.any() {
1704 let minus_one = -Self::ONE;
1705 x2 = both_infinite.select(x2 & minus_one, x2);
1706 y2 = both_infinite.select(y2 & minus_one, y2);
1707 }
1708
1709 let t = y2 / x2;
1711
1712 let notbig = t.simd_le(T3PO8);
1716 let notsmal = t.simd_ge(Self::splat(0.66));
1717
1718 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1719 s = notsmal & s;
1720 let mut fac = notbig.select(MORE_BITS_O2, MORE_BITS);
1721 fac = notsmal & fac;
1722
1723 let mut a = notbig & t;
1727 a = notsmal.select(a - Self::ONE, a);
1728 let mut b = notbig & Self::ONE;
1729 b = notsmal.select(b + t, b);
1730 let z = a / b;
1731
1732 let zz = z * z;
1733
1734 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1735 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1736
1737 let mut re = (px / qx).mul_add(z * zz, z);
1738 re += s + fac;
1739
1740 re = swapxy.select(Self::FRAC_PI_2 - re, re);
1742 re = ((x | y).simd_eq(Self::ZERO)).select(Self::ZERO, re);
1743 re = (x.is_sign_negative()).select(Self::PI - re, re);
1744
1745 re = (y.is_sign_negative()).select(-re, re);
1747
1748 re
1749 }
1750
1751 #[inline]
1752 pub fn sin_cos(self) -> (Self, Self) {
1753 const_f64_as_f64x2!(P0sin, -1.66666666666666307295E-1);
1757 const_f64_as_f64x2!(P1sin, 8.33333333332211858878E-3);
1758 const_f64_as_f64x2!(P2sin, -1.98412698295895385996E-4);
1759 const_f64_as_f64x2!(P3sin, 2.75573136213857245213E-6);
1760 const_f64_as_f64x2!(P4sin, -2.50507477628578072866E-8);
1761 const_f64_as_f64x2!(P5sin, 1.58962301576546568060E-10);
1762
1763 const_f64_as_f64x2!(P0cos, 4.16666666666665929218E-2);
1764 const_f64_as_f64x2!(P1cos, -1.38888888888730564116E-3);
1765 const_f64_as_f64x2!(P2cos, 2.48015872888517045348E-5);
1766 const_f64_as_f64x2!(P3cos, -2.75573141792967388112E-7);
1767 const_f64_as_f64x2!(P4cos, 2.08757008419747316778E-9);
1768 const_f64_as_f64x2!(P5cos, -1.13585365213876817300E-11);
1769
1770 const_f64_as_f64x2!(DP1, 7.853981554508209228515625E-1 * 2.);
1771 const_f64_as_f64x2!(DP2, 7.94662735614792836714E-9 * 2.);
1772 const_f64_as_f64x2!(DP3, 3.06161699786838294307E-17 * 2.);
1773
1774 const_f64_as_f64x2!(TWO_OVER_PI, 2.0 / core::f64::consts::PI);
1775
1776 let xa = self.abs();
1777
1778 let y = (xa * TWO_OVER_PI).round_ties_even();
1779 let q = y.round_int();
1780
1781 let x = y.mul_neg_add(DP3, y.mul_neg_add(DP2, y.mul_neg_add(DP1, xa)));
1782
1783 let x2 = x * x;
1784 let mut s = polynomial_5!(x2, P0sin, P1sin, P2sin, P3sin, P4sin, P5sin);
1785 let mut c = polynomial_5!(x2, P0cos, P1cos, P2cos, P3cos, P4cos, P5cos);
1786 s = (x * x2).mul_add(s, x);
1787 c =
1788 (x2 * x2).mul_add(c, x2.mul_neg_add(f64x2::from(0.5), f64x2::from(1.0)));
1789
1790 let swap = !((q & i64x2::from(1)).simd_eq(i64x2::from(0)));
1791
1792 let mut overflow: f64x2 = cast(q.simd_gt(i64x2::from(0x80000000000000)));
1793 overflow &= xa.is_finite();
1794 s = overflow.select(f64x2::from(0.0), s);
1795 c = overflow.select(f64x2::from(1.0), c);
1796
1797 let mut sin1 = cast::<_, f64x2>(swap).select(c, s);
1799 let sign_sin: i64x2 = (q << 62) ^ cast::<_, i64x2>(self);
1800 sin1 = sin1.flip_signs(cast(sign_sin));
1801
1802 let mut cos1 = cast::<_, f64x2>(swap).select(s, c);
1804 let sign_cos: i64x2 = ((q + i64x2::from(1)) & i64x2::from(2)) << 62;
1805 cos1 ^= cast::<_, f64x2>(sign_cos);
1806
1807 let finite = self.is_finite();
1809 let nan = Self::splat(f64::NAN);
1810 let sin_final = finite.select(sin1, nan);
1811 let cos_final = finite.select(cos1, nan);
1812
1813 (sin_final, cos_final)
1814 }
1815
1816 #[inline]
1817 pub fn asin_acos(self) -> (Self, Self) {
1818 const_f64_as_f64x2!(R4asin, 2.967721961301243206100E-3);
1821 const_f64_as_f64x2!(R3asin, -5.634242780008963776856E-1);
1822 const_f64_as_f64x2!(R2asin, 6.968710824104713396794E0);
1823 const_f64_as_f64x2!(R1asin, -2.556901049652824852289E1);
1824 const_f64_as_f64x2!(R0asin, 2.853665548261061424989E1);
1825
1826 const_f64_as_f64x2!(S3asin, -2.194779531642920639778E1);
1827 const_f64_as_f64x2!(S2asin, 1.470656354026814941758E2);
1828 const_f64_as_f64x2!(S1asin, -3.838770957603691357202E2);
1829 const_f64_as_f64x2!(S0asin, 3.424398657913078477438E2);
1830
1831 const_f64_as_f64x2!(P5asin, 4.253011369004428248960E-3);
1832 const_f64_as_f64x2!(P4asin, -6.019598008014123785661E-1);
1833 const_f64_as_f64x2!(P3asin, 5.444622390564711410273E0);
1834 const_f64_as_f64x2!(P2asin, -1.626247967210700244449E1);
1835 const_f64_as_f64x2!(P1asin, 1.956261983317594739197E1);
1836 const_f64_as_f64x2!(P0asin, -8.198089802484824371615E0);
1837
1838 const_f64_as_f64x2!(Q4asin, -1.474091372988853791896E1);
1839 const_f64_as_f64x2!(Q3asin, 7.049610280856842141659E1);
1840 const_f64_as_f64x2!(Q2asin, -1.471791292232726029859E2);
1841 const_f64_as_f64x2!(Q1asin, 1.395105614657485689735E2);
1842 const_f64_as_f64x2!(Q0asin, -4.918853881490881290097E1);
1843
1844 let xa = self.abs();
1845
1846 let big = xa.simd_ge(f64x2::splat(0.625));
1847
1848 let x1 = big.select(f64x2::splat(1.0) - xa, xa * xa);
1849
1850 let x2 = x1 * x1;
1851 let x3 = x2 * x1;
1852 let x4 = x2 * x2;
1853 let x5 = x4 * x1;
1854
1855 let do_big = big.any();
1856 let do_small = !big.all();
1857
1858 let mut rx = f64x2::default();
1859 let mut sx = f64x2::default();
1860 let mut px = f64x2::default();
1861 let mut qx = f64x2::default();
1862
1863 if do_big {
1864 rx = x3.mul_add(R3asin, x2 * R2asin)
1865 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1866 sx =
1867 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1868 }
1869 if do_small {
1870 px = x3.mul_add(P3asin, P0asin)
1871 + x4.mul_add(P4asin, x1 * P1asin)
1872 + x5.mul_add(P5asin, x2 * P2asin);
1873 qx = x4.mul_add(Q4asin, x5)
1874 + x3.mul_add(Q3asin, x1 * Q1asin)
1875 + x2.mul_add(Q2asin, Q0asin);
1876 };
1877
1878 let vx = big.select(rx, px);
1879 let wx = big.select(sx, qx);
1880
1881 let y1 = vx / wx * x1;
1882
1883 let mut z1 = f64x2::default();
1884 let mut z2 = f64x2::default();
1885 if do_big {
1886 let xb = (x1 + x1).sqrt();
1887 z1 = xb.mul_add(y1, xb);
1888 }
1889
1890 if do_small {
1891 z2 = xa.mul_add(y1, xa);
1892 }
1893
1894 let z3 = f64x2::FRAC_PI_2 - z1;
1896 let asin = big.select(z3, z2);
1897 let asin = asin.flip_signs(self);
1898
1899 let z3 = self.simd_lt(f64x2::ZERO).select(f64x2::PI - z1, z1);
1901 let z4 = f64x2::FRAC_PI_2 - z2.flip_signs(self);
1902 let acos = big.select(z3, z4);
1903
1904 (asin, acos)
1905 }
1906
1907 #[inline]
1908 pub fn exp_m1(self) -> Self {
1909 const_f64_as_f64x2!(P2, 1.0 / 2.0);
1910 const_f64_as_f64x2!(P3, 1.0 / 6.0);
1911 const_f64_as_f64x2!(P4, 1.0 / 24.0);
1912 const_f64_as_f64x2!(P5, 1.0 / 120.0);
1913 const_f64_as_f64x2!(P6, 1.0 / 720.0);
1914 const_f64_as_f64x2!(P7, 1.0 / 5040.0);
1915 const_f64_as_f64x2!(P8, 1.0 / 40320.0);
1916 const_f64_as_f64x2!(P9, 1.0 / 362880.0);
1917 const_f64_as_f64x2!(P10, 1.0 / 3628800.0);
1918 const_f64_as_f64x2!(P11, 1.0 / 39916800.0);
1919 const_f64_as_f64x2!(P12, 1.0 / 479001600.0);
1920 const_f64_as_f64x2!(P13, 1.0 / 6227020800.0);
1921 const_f64_as_f64x2!(LN2D_HI, 0.693145751953125);
1924 const_f64_as_f64x2!(LN2D_LO, 1.42860682030941723212E-6);
1925 if self.simd_lt(Self::from(-37.429)).all() {
1929 return Self::from(-1.0);
1930 }
1931 let max_x = Self::from(709.783);
1935 let min_x = Self::from(-744.79);
1936 let max_r = Self::from(1023.0);
1937 let r = (self * Self::LOG2_E).round_ties_even();
1938 let big = r.simd_gt(max_r);
1939 let r_safe = big.select(max_r, r);
1940 let excess = r - max_r;
1941 let excess = big.select(excess, Self::ZERO);
1942 let scale = Self::vm_pow2n(excess);
1943 let x = r.mul_neg_add(LN2D_HI, self);
1944 let x = r.mul_neg_add(LN2D_LO, x);
1945 let z =
1946 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1947 let n2 = Self::vm_pow2n(r_safe);
1948 let exp_val = (z + Self::ONE) * scale * n2;
1949 let r_is_zero = r.simd_eq(Self::ZERO);
1953 let z = r_is_zero.select(z, exp_val - Self::ONE);
1954 let nan_mask = self.is_nan();
1955 let finite = self.is_finite();
1956 let mut result = nan_mask.select(Self::nan_pow(), z);
1957 let pos_overflow = self.simd_gt(max_x) & finite;
1958 result = pos_overflow.select(Self::infinity(), result);
1959 let neg_underflow = self.simd_lt(min_x) & finite;
1960 result = neg_underflow.select(-Self::ONE, result);
1961 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1962 result = pos_inf.select(Self::infinity(), result);
1963 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1964 result = neg_inf.select(-Self::ONE, result);
1965 let is_zero = self.simd_eq(Self::ZERO);
1966 result = is_zero.select(self, result);
1967 result
1968 }
1969
1970 #[inline]
1971 pub fn ln_1p(self) -> Self {
1972 let u = self + Self::ONE;
1980 let eq = u.simd_eq(Self::ONE);
1981 let ln_u = Self::ln(u);
1982 let correction = self * (ln_u / (u - Self::ONE));
1983 let result = eq.select(self, correction);
1984 let over = u.is_inf();
1985 over.select(ln_u, result)
1986 }
1987
1988 #[inline]
1989 pub fn sinh(self) -> Self {
1990 const_f64_as_f64x2!(P0, 1.0);
1991 const_f64_as_f64x2!(P1, 1.0 / 6.0);
1992 const_f64_as_f64x2!(P2, 1.0 / 120.0);
1993 const_f64_as_f64x2!(P3, 1.0 / 5040.0);
1994 const_f64_as_f64x2!(P4, 1.0 / 362880.0);
1995 const_f64_as_f64x2!(P5, 1.0 / 39916800.0);
1996 const_f64_as_f64x2!(P6, 1.0 / 6227020800.0);
1997 let a = self.abs();
1998 let small = a.simd_lt(f64x2::from(0.5));
2000 let t = a * a;
2001 let poly = a * polynomial_6!(t, P0, P1, P2, P3, P4, P5, P6);
2002 let exp_based = {
2003 let e = a.exp();
2004 (e - Self::ONE / e) * Self::HALF
2005 };
2006 let result = small.select(poly, exp_based);
2007 result.flip_signs(self)
2008 }
2009
2010 #[inline]
2011 pub fn cosh(self) -> Self {
2012 const_f64_as_f64x2!(P0, 1.0);
2013 const_f64_as_f64x2!(P1, 1.0 / 2.0);
2014 const_f64_as_f64x2!(P2, 1.0 / 24.0);
2015 const_f64_as_f64x2!(P3, 1.0 / 720.0);
2016 const_f64_as_f64x2!(P4, 1.0 / 40320.0);
2017 const_f64_as_f64x2!(P5, 1.0 / 3628800.0);
2018 const_f64_as_f64x2!(P6, 1.0 / 479001600.0);
2019 const_f64_as_f64x2!(P7, 1.0 / 87178291200.0);
2020 let a = self.abs();
2021 let small = a.simd_lt(f64x2::from(0.5));
2023 let t = a * a;
2024 let poly = polynomial_7!(t, P0, P1, P2, P3, P4, P5, P6, P7);
2025 let exp_based = {
2026 let e = a.exp();
2027 (e + Self::ONE / e) * Self::HALF
2028 };
2029 small.select(poly, exp_based)
2030 }
2031
2032 #[inline]
2033 pub fn tanh(self) -> Self {
2034 let a = self.abs();
2038 let large = a.simd_gt(f64x2::from(19.062));
2039 if large.all() {
2040 return Self::ONE.flip_signs(self);
2041 }
2042 let small = a.simd_lt(f64x2::from(5e-8));
2043 let exp_based = {
2044 let t = (Self::from(-2.0) * a).exp_m1();
2045 let pos = -t / (t + Self::from(2.0));
2046 pos.flip_signs(self)
2047 };
2048 let result = small.select(self, exp_based);
2049 large.select(Self::ONE.flip_signs(self), result)
2050 }
2051}
2052
2053impl f64x2 {
2056 #[inline]
2057 fn vm_pow2n(self) -> Self {
2058 const_f64_as_f64x2!(pow2_52, 4503599627370496.0);
2059 const_f64_as_f64x2!(bias, 1023.0);
2060 let a = self + (bias + pow2_52);
2061 let c = cast::<_, i64x2>(a) << 52;
2062 let std_result = cast::<_, f64x2>(c);
2063
2064 let min_exp = f64x2::from(-1022.0);
2065 let is_sub = self.simd_lt(min_exp);
2066 if is_sub.any() {
2067 let valid = self.simd_ge(f64x2::from(-1074.0));
2068 let shift_f = self + f64x2::from(1074.0);
2069 let mut shift_i = shift_f.trunc_int();
2070 shift_i = cast::<_, i64x2>(valid).select(shift_i, i64x2::ZERO);
2071 let mantissa = i64x2::ONE << shift_i;
2072 let sub_result = cast::<_, f64x2>(mantissa);
2073 let sub_result = valid.select(sub_result, f64x2::ZERO);
2074 is_sub.select(sub_result, std_result)
2075 } else {
2076 std_result
2077 }
2078 }
2079
2080 #[inline]
2081 fn exponent(self) -> f64x2 {
2082 const_f64_as_f64x2!(pow2_52, 4503599627370496.0);
2083 const_f64_as_f64x2!(bias, 1023.0);
2084 let a = cast::<_, u64x2>(self);
2085 let b = a >> 52;
2086 let c = b | cast::<_, u64x2>(pow2_52);
2087 let d = cast::<_, f64x2>(c);
2088 let e = d - (pow2_52 + bias);
2089 e
2090 }
2091
2092 #[inline]
2093 fn fraction_2(self) -> Self {
2094 let t1 = cast::<_, u64x2>(self);
2095 let t2 = cast::<_, u64x2>(
2096 (t1 & u64x2::from(0x000FFFFFFFFFFFFF)) | u64x2::from(0x3FE0000000000000),
2097 );
2098 cast::<_, f64x2>(t2)
2099 }
2100
2101 #[inline]
2102 fn is_zero_or_subnormal(self) -> Self {
2103 let t = cast::<_, i64x2>(self);
2104 let t = t & i64x2::splat(0x7FF0000000000000);
2105 let mask = t.simd_eq(i64x2::splat(0));
2106 cast::<_, f64x2>(mask)
2107 }
2108
2109 #[inline]
2110 fn infinity() -> Self {
2111 cast::<_, f64x2>(i64x2::splat(0x7FF0000000000000))
2112 }
2113
2114 #[inline]
2115 fn nan_log() -> Self {
2116 cast::<_, f64x2>(i64x2::splat(0x7FF8000000000000 | 0x101 << 29))
2117 }
2118
2119 #[inline]
2120 fn nan_pow() -> Self {
2121 cast::<_, f64x2>(i64x2::splat(0x7FF8000000000000 | 0x101 << 29))
2122 }
2123
2124 #[must_use]
2126 #[inline]
2127 #[allow(dead_code)]
2128 pub(crate) fn unpack_lo(self, b: Self) -> Self {
2129 pick! {
2130 if #[cfg(target_feature="sse2")] {
2131 Self { sse: unpack_low_m128d(self.sse, b.sse) }
2132 } else if #[cfg(target_feature="simd128")] {
2133 Self { simd: i64x2_shuffle::<0, 2>(self.simd, b.simd) }
2134 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2135 Self { neon: unsafe { vzip1q_f64(self.neon, b.neon) } }
2136 } else {
2137 Self::new([self.as_array()[0], b.as_array()[0]])
2138 }
2139 }
2140 }
2141
2142 #[must_use]
2144 #[inline]
2145 #[allow(dead_code)]
2146 pub(crate) fn unpack_hi(self, b: Self) -> Self {
2147 pick! {
2148 if #[cfg(target_feature="sse2")] {
2149 Self { sse: unpack_high_m128d(self.sse, b.sse) }
2150 } else if #[cfg(target_feature="simd128")] {
2151 Self { simd: i64x2_shuffle::<1, 3>(self.simd, b.simd) }
2152 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2153 Self { neon: unsafe { vzip2q_f64(self.neon, b.neon) } }
2154 } else {
2155 Self::new([self.as_array()[1], b.as_array()[1]])
2156 }
2157 }
2158 }
2159
2160 #[inline]
2163 pub fn from_i32x4_lower2(v: i32x4) -> Self {
2164 pick! {
2165 if #[cfg(target_feature="sse2")] {
2166 Self { sse: convert_to_m128d_from_lower2_i32_m128i(v.sse) }
2167 } else if #[cfg(target_feature="simd128")] {
2168 Self { simd: f64x2_convert_low_i32x4(v.simd)}
2169 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
2170 Self { neon: unsafe { vcvtq_f64_s64(vmovl_s32(vget_low_s32(v.neon))) }}
2171 } else {
2172 Self { arr: [
2173 v.as_array()[0] as f64,
2174 v.as_array()[1] as f64,
2175 ]}
2176 }
2177 }
2178 }
2179}
2180
2181impl From<i32x4> for f64x2 {
2182 #[inline]
2185 fn from(v: i32x4) -> Self {
2186 Self::from_i32x4_lower2(v)
2187 }
2188}