1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx512f")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
12 #[repr(C, align(64))]
13 pub struct f64x8 { pub(crate) avx512: m512d }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq)]
22 #[repr(C, align(64))]
23 pub struct f64x8 { pub(crate) a : f64x4, pub(crate) b : f64x4 }
24 }
25}
26
27macro_rules! const_f64_as_f64x8 {
28 ($i:ident, $f:expr) => {
29 #[allow(non_upper_case_globals)]
30 pub const $i: f64x8 = f64x8::new([$f; 8]);
31 };
32}
33
34impl_simd_float! {
35 unsafe {
36 T = f64,
37 N = 8,
38 Simd = f64x8,
39 IntSimd = i64x8,
40 UintT = u64,
41 UintSimd = u64x8,
42 optional_type_x86_inner { X86Inner = __m512d },
43 optional_type_arm_inner {},
44 optional_type_wasm_inner {},
45 }
46 old_powf_simd_fn_name = pow_f64x8,
47
48 #[inline]
49 fn neg(self) -> Self::Output {
50 pick! {
51 if #[cfg(target_feature="avx512f")] {
52 Self { avx512: bitxor_m512d(self.avx512, Self::splat(-0.0).avx512) }
53 } else {
54 Self {
55 a : self.a.neg(),
56 b : self.b.neg(),
57 }
58 }
59 }
60 }
61
62 #[inline]
63 fn not(self) -> Self::Output {
64 pick! {
65 if #[cfg(target_feature="avx512f")] {
66 Self { avx512: bitxor_m512d(self.avx512, set_splat_m512d(f64::from_bits(u64::MAX))) }
67 } else {
68 Self {
69 a : self.a.not(),
70 b : self.b.not(),
71 }
72 }
73 }
74 }
75
76 #[inline]
77 fn add(self, rhs: Self) -> Self::Output {
78 pick! {
79 if #[cfg(target_feature="avx512f")] {
80 Self { avx512: add_m512d(self.avx512, rhs.avx512) }
81 } else {
82 Self {
83 a : self.a.add(rhs.a),
84 b : self.b.add(rhs.b),
85 }
86 }
87 }
88 }
89
90 #[inline]
91 fn sub(self, rhs: Self) -> Self::Output {
92 pick! {
93 if #[cfg(target_feature="avx512f")] {
94 Self { avx512: sub_m512d(self.avx512, rhs.avx512) }
95 } else {
96 Self {
97 a : self.a.sub(rhs.a),
98 b : self.b.sub(rhs.b),
99 }
100 }
101 }
102 }
103
104 #[inline]
105 fn mul(self, rhs: Self) -> Self::Output {
106 pick! {
107 if #[cfg(target_feature="avx512f")] {
108 Self { avx512: mul_m512d(self.avx512, rhs.avx512) }
109 } else {
110 Self { a: self.a.mul(rhs.a), b: self.b.mul(rhs.b) }
111 }
112 }
113 }
114
115 #[inline]
116 fn div(self, rhs: Self) -> Self::Output {
117 pick! {
118 if #[cfg(target_feature="avx512f")] {
119 Self { avx512: div_m512d(self.avx512, rhs.avx512) }
120 } else {
121 Self { a: self.a.div(rhs.a), b: self.b.div(rhs.b) }
122 }
123 }
124 }
125
126 #[inline]
127 fn rem(self, rhs: Self) -> Self::Output {
128 Self::new([
129 self.to_array()[0] % rhs.to_array()[0],
130 self.to_array()[1] % rhs.to_array()[1],
131 self.to_array()[2] % rhs.to_array()[2],
132 self.to_array()[3] % rhs.to_array()[3],
133 self.to_array()[4] % rhs.to_array()[4],
134 self.to_array()[5] % rhs.to_array()[5],
135 self.to_array()[6] % rhs.to_array()[6],
136 self.to_array()[7] % rhs.to_array()[7],
137 ])
138 }
139
140 #[inline]
141 fn bitand(self, rhs: Self) -> Self::Output {
142 pick! {
143 if #[cfg(target_feature="avx512f")] {
144 Self { avx512: bitand_m512d(self.avx512, rhs.avx512) }
145 } else {
146 Self {
147 a : self.a.bitand(rhs.a),
148 b : self.b.bitand(rhs.b),
149 }
150 }
151 }
152 }
153
154 #[inline]
155 fn bitor(self, rhs: Self) -> Self::Output {
156 pick! {
157 if #[cfg(target_feature="avx512f")] {
158 Self { avx512: bitor_m512d(self.avx512, rhs.avx512) }
159 } else {
160 Self {
161 a : self.a.bitor(rhs.a),
162 b : self.b.bitor(rhs.b),
163 }
164 }
165 }
166 }
167
168 #[inline]
169 fn bitxor(self, rhs: Self) -> Self::Output {
170 pick! {
171 if #[cfg(target_feature="avx512f")] {
172 Self { avx512: bitxor_m512d(self.avx512, rhs.avx512) }
173 } else {
174 Self {
175 a : self.a.bitxor(rhs.a),
176 b : self.b.bitxor(rhs.b),
177 }
178 }
179 }
180 }
181
182 #[inline]
183 fn simd_eq(self, rhs: Self) -> Self::Output {
184 pick! {
185 if #[cfg(target_feature="avx512f")] {
186 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(EqualOrdered)}>(self.avx512, rhs.avx512) }
187 } else {
188 Self {
189 a : self.a.simd_eq(rhs.a),
190 b : self.b.simd_eq(rhs.b),
191 }
192 }
193 }
194 }
195
196 #[inline]
197 fn simd_ne(self, rhs: Self) -> Self::Output {
198 pick! {
199 if #[cfg(target_feature="avx512f")] {
200 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(NotEqualUnordered)}>(self.avx512, rhs.avx512) }
201 } else {
202 Self {
203 a : self.a.simd_ne(rhs.a),
204 b : self.b.simd_ne(rhs.b),
205 }
206 }
207 }
208 }
209
210 #[inline]
211 fn simd_lt(self, rhs: Self) -> Self::Output {
212 pick! {
213 if #[cfg(target_feature="avx512f")] {
214 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(LessThanOrdered)}>(self.avx512, rhs.avx512) }
215 } else {
216 Self {
217 a : self.a.simd_lt(rhs.a),
218 b : self.b.simd_lt(rhs.b),
219 }
220 }
221 }
222 }
223
224 #[inline]
225 fn simd_gt(self, rhs: Self) -> Self::Output {
226 pick! {
227 if #[cfg(target_feature="avx512f")] {
228 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(GreaterThanOrdered)}>(self.avx512, rhs.avx512) }
229 } else {
230 Self {
231 a : self.a.simd_gt(rhs.a),
232 b : self.b.simd_gt(rhs.b),
233 }
234 }
235 }
236 }
237
238 #[inline]
239 fn simd_le(self, rhs: Self) -> Self::Output {
240 pick! {
241 if #[cfg(target_feature="avx512f")] {
242 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(LessEqualOrdered)}>(self.avx512, rhs.avx512) }
243 } else {
244 Self {
245 a : self.a.simd_le(rhs.a),
246 b : self.b.simd_le(rhs.b),
247 }
248 }
249 }
250 }
251
252 #[inline]
253 fn simd_ge(self, rhs: Self) -> Self::Output {
254 pick! {
255 if #[cfg(target_feature="avx512f")] {
256 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(GreaterEqualOrdered)}>(self.avx512, rhs.avx512) }
257 } else {
258 Self {
259 a : self.a.simd_ge(rhs.a),
260 b : self.b.simd_ge(rhs.b),
261 }
262 }
263 }
264 }
265
266 #[inline]
267 pub fn reduce_add(self) -> f64 {
268 pick! {
269 if #[cfg(target_feature="avx512f")] {
270 let lo = cast_to_m256d_from_m512d(self.avx512);
272 let hi = extract_m256d_from_m512d::<1>(self.avx512);
273 let v = add_m256d(lo, hi); let t = add_horizontal_m256d(v, v); let lo = cast_to_m128d_from_m256d(t); let hi = extract_m128d_from_m256d::<1>(t); let s = add_m128d(lo, hi); get_f64_from_m128d_s(s)
279 } else {
280 self.a.reduce_add() + self.b.reduce_add()
281 }
282 }
283 }
284
285 #[inline]
286 pub fn reduce_mul(self) -> f64 {
287 pick! {
288 if #[cfg(target_feature="avx512f")] {
289 let lo = cast_to_m256d_from_m512d(self.avx512);
291 let hi = extract_m256d_from_m512d::<1>(self.avx512);
292 let v = mul_m256d(lo, hi);
293 let lo = cast_to_m128d_from_m256d(v);
294 let hi = extract_m128d_from_m256d::<1>(v);
295 let lo = mul_m128d(lo,hi);
296 let hi64 = unpack_high_m128d(lo,lo);
297 let product = mul_m128d_s(lo,hi64);
298 get_f64_from_m128d_s(product)
299 } else {
300 self.a.reduce_mul() * self.b.reduce_mul()
301 }
302 }
303 }
304
305 #[inline]
306 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
307 pick! {
308 if #[cfg(target_feature="avx512f")] {
309 Self {
310 avx512: bitor_m512d(
311 bitand_m512d(if_one.avx512, self.avx512),
312 bitandnot_m512d(self.avx512, if_zero.avx512),
313 ),
314 }
315 } else {
316 Self {
317 a: self.a.bitselect(if_one.a, if_zero.a),
318 b: self.b.bitselect(if_one.b, if_zero.b),
319 }
320 }
321 }
322 }
323
324 #[inline]
325 fn select(self, if_true: Self, if_false: Self) -> Self {
326 pick! {
327 if #[cfg(target_feature="avx512f")] {
328 Self { avx512: blend_varying_m512d(if_false.avx512, if_true.avx512, movepi64_mask_m512d(self.avx512)) }
329 } else {
330 Self {
331 a : self.a.select(if_true.a, if_false.a),
332 b : self.b.select(if_true.b, if_false.b),
333 }
334 }
335 }
336 }
337
338 #[inline]
339 pub fn to_bitmask(self) -> u32 {
340 pick! {
341 if #[cfg(target_feature="avx512f")] {
342 movepi64_mask_m512d(self.avx512) as u32
343 } else {
344 (self.b.to_bitmask() << 4) | self.a.to_bitmask()
345 }
346 }
347 }
348
349 #[inline]
350 pub fn any(self) -> bool {
351 pick! {
352 if #[cfg(target_feature="avx512f")] {
353 movepi64_mask_m512d(self.avx512) != 0
354 } else {
355 self.a.any() || self.b.any()
356 }
357 }
358 }
359
360 #[inline]
361 pub fn all(self) -> bool {
362 pick! {
363 if #[cfg(target_feature="avx512f")] {
364 movepi64_mask_m512d(self.avx512) == 0b11111111
365 } else {
366 self.a.all() && self.b.all()
367 }
368 }
369 }
370
371 #[inline]
374 pub fn transpose(data: [f64x8; 8]) -> [f64x8; 8] {
375 #[inline(always)]
378 fn transpose_column(data: &[f64x8; 8], index: usize) -> f64x8 {
379 f64x8::new([
380 data[0].as_array()[index],
381 data[1].as_array()[index],
382 data[2].as_array()[index],
383 data[3].as_array()[index],
384 data[4].as_array()[index],
385 data[5].as_array()[index],
386 data[6].as_array()[index],
387 data[7].as_array()[index],
388 ])
389 }
390
391 [
392 transpose_column(&data, 0),
393 transpose_column(&data, 1),
394 transpose_column(&data, 2),
395 transpose_column(&data, 3),
396 transpose_column(&data, 4),
397 transpose_column(&data, 5),
398 transpose_column(&data, 6),
399 transpose_column(&data, 7),
400 ]
401 }
402
403 #[inline]
404 pub fn is_nan(self) -> Self {
405 pick! {
406 if #[cfg(target_feature="avx512f")] {
407 Self { avx512: cmp_op_mask_m512d::<{cmp_op!(Unordered)}>(self.avx512, self.avx512) }
408 } else {
409 Self {
410 a: self.a.is_nan(),
411 b: self.b.is_nan(),
412 }
413 }
414 }
415 }
416
417 #[inline]
418 pub fn is_inf(self) -> Self {
419 let shifted_inf = u64x8::from(0xFFE0000000000000);
420 let u: u64x8 = cast(self);
421 let shift_u = u << 1_u64;
422 let out = (shift_u).simd_eq(shifted_inf);
423 cast(out)
424 }
425
426 #[inline]
427 pub fn is_finite(self) -> Self {
428 let shifted_exp_mask = u64x8::splat(0xFFE0000000000000);
429 let u: u64x8 = cast(self);
430 let shift_u = u << 1_u64;
431 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
432 cast(out)
433 }
434
435 #[inline]
436 pub fn is_sign_positive(self) -> Self {
437 const SIGN_MASK: u64x8 = u64x8::splat((-0.0_f64).to_bits());
438
439 let bits = cast::<f64x8, u64x8>(self);
440 let sign = bits & SIGN_MASK;
441 let result = sign.simd_eq(u64x8::ZERO);
442 cast::<u64x8, f64x8>(result)
443 }
444
445 #[inline]
446 pub fn is_sign_negative(self) -> Self {
447 const SIGN_MASK: u64x8 = u64x8::splat((-0.0_f64).to_bits());
448
449 let bits = cast::<f64x8, u64x8>(self);
450 let sign = bits & SIGN_MASK;
451 let result = sign.simd_eq(SIGN_MASK);
452 cast::<u64x8, f64x8>(result)
453 }
454
455 #[inline]
456 pub fn recip(self) -> Self {
457 Self::ONE / self
460 }
461
462 #[inline]
463 pub fn recip_sqrt(self) -> Self {
464 Self::ONE / self.sqrt()
467 }
468
469 #[inline]
470 pub fn max(self, rhs: Self) -> Self {
471 pick! {
472 if #[cfg(target_feature="avx512f")] {
473 rhs.is_nan().select(self, Self { avx512: max_m512d(self.avx512, rhs.avx512) })
474 } else {
475 Self {
476 a: self.a.max(rhs.a),
477 b: self.b.max(rhs.b),
478 }
479 }
480 }
481 }
482
483 #[inline]
484 pub fn fast_max(self, rhs: Self) -> Self {
485 pick! {
486 if #[cfg(target_feature="avx512f")] {
487 Self { avx512: max_m512d(self.avx512, rhs.avx512) }
488 } else {
489 Self {
490 a : self.a.fast_max(rhs.a),
491 b : self.b.fast_max(rhs.b),
492 }
493 }
494 }
495 }
496
497 #[inline]
498 pub fn min(self, rhs: Self) -> Self {
499 pick! {
500 if #[cfg(target_feature="avx512f")] {
501 rhs.is_nan().select(self, Self { avx512: min_m512d(self.avx512, rhs.avx512) })
502 } else {
503 Self {
504 a: self.a.min(rhs.a),
505 b: self.b.min(rhs.b),
506 }
507 }
508 }
509 }
510
511 #[inline]
512 pub fn fast_min(self, rhs: Self) -> Self {
513 pick! {
514 if #[cfg(target_feature="avx512f")] {
515 Self { avx512: min_m512d(self.avx512, rhs.avx512) }
516 } else {
517 Self {
518 a : self.a.fast_min(rhs.a),
519 b : self.b.fast_min(rhs.b),
520 }
521 }
522 }
523 }
524
525 #[inline]
526 pub fn clamp(self, min: Self, max: Self) -> Self {
527 pick! {
528 if #[cfg(target_feature="avx512f")] {
529 self.fast_clamp(min, max) | min.is_nan() | max.is_nan()
531 } else {
532 Self {
534 a: self.a.clamp(min.a, max.a),
535 b: self.b.clamp(min.b, max.b),
536 }
537 }
538 }
539 }
540
541 #[inline]
542 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
543 pick! {
544 if #[cfg(target_feature="avx512f")] {
545 Self { avx512: max_m512d(min.avx512, min_m512d(max.avx512, self.avx512)) }
548 } else {
549 Self {
550 a: self.a.fast_clamp(min.a, max.a),
551 b: self.b.fast_clamp(min.b, max.b),
552 }
553 }
554 }
555 }
556
557 #[inline]
558 pub fn abs(self) -> Self {
559 pick! {
560 if #[cfg(target_feature="avx512f")] {
561 let non_sign_bits = f64x8::from(f64::from_bits(i64::MAX as u64));
562 self & non_sign_bits
563 } else {
564 Self {
565 a: self.a.abs(),
566 b: self.b.abs(),
567 }
568 }
569 }
570 }
571
572 #[inline]
573 pub fn floor(self) -> Self {
574 pick! {
575 if #[cfg(target_feature="avx512f")] {
576 Self { avx512: round_m512d::<{round_op!(NegInf)}>(self.avx512) }
577 } else {
578 Self {
579 a : self.a.floor(),
580 b : self.b.floor(),
581 }
582 }
583 }
584 }
585
586 #[inline]
587 pub fn ceil(self) -> Self {
588 pick! {
589 if #[cfg(target_feature="avx512f")] {
590 Self { avx512: round_m512d::<{round_op!(PosInf)}>(self.avx512) }
591 } else {
592 Self {
593 a : self.a.ceil(),
594 b : self.b.ceil(),
595 }
596 }
597 }
598 }
599
600 #[inline]
601 pub fn round(self) -> Self {
602 pick! {
603 if #[cfg(target_feature="avx512f")] {
604 const_f64_as_f64x8!(HALF_NEXT_DOWN, 0.5_f64.next_down());
605 const_f64_as_f64x8!(BOUNDS_LIMIT, 4503599627370496.0);
606
607 let self_abs = self.abs();
608
609 let adjusted_self = self_abs + Self::HALF;
610 let result_abs = Self { avx512: round_m512d::<{round_op!(Zero)}>(adjusted_self.avx512) };
611 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
614
615 let bounds_mask: Self = cast(cmp_op_mask_i64_m512i::<{cmp_int_op!(Lt)}>(
617 cast(self_abs),
618 cast(BOUNDS_LIMIT),
619 ));
620
621 bounds_mask.abs().bitselect(result_abs, self)
623 } else {
624 Self {
625 a: self.a.round(),
626 b: self.b.round(),
627 }
628 }
629 }
630 }
631
632 #[inline]
633 pub fn round_int(self) -> i64x8 {
634 pick! {
635 if #[cfg(target_feature="avx512dq")] {
636 #[cfg(target_arch = "x86")]
637 use core::arch::x86::_mm512_cvtpd_epi64;
638 #[cfg(target_arch = "x86_64")]
639 use core::arch::x86_64::_mm512_cvtpd_epi64;
640
641 let non_nan_mask = self.simd_eq(self);
643 let non_nan = self & non_nan_mask;
644 let flip_to_max: i64x8 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
645
646 let cast: i64x8 = cast(m512i(unsafe { _mm512_cvtpd_epi64(non_nan.avx512.0) }));
648 flip_to_max ^ cast
649 } else {
650 let [a,b]: [f64x4;2] = cast(self);
651 cast([
652 a.round_int(),
653 b.round_int(),
654 ])
655 }
656 }
657 }
658
659 #[inline]
660 pub fn fast_round_int(self) -> i64x8 {
661 pick! {
662 if #[cfg(target_feature="avx512dq")] {
663 #[cfg(target_arch = "x86")]
664 use core::arch::x86::_mm512_cvtpd_epi64;
665 #[cfg(target_arch = "x86_64")]
666 use core::arch::x86_64::_mm512_cvtpd_epi64;
667
668 cast(m512i(unsafe { _mm512_cvtpd_epi64(self.avx512.0) }))
670 } else {
671
672 let [a,b]: [f64x4;2] = cast(self);
673 cast([
674 a.fast_round_int(),
675 b.fast_round_int(),
676 ])
677 }
678 }
679 }
680
681 #[inline]
682 pub fn round_ties_even(self) -> Self {
683 pick! {
684 if #[cfg(target_feature="avx512f")] {
685 Self { avx512: round_m512d::<{round_op!(Nearest)}>(self.avx512) }
686 } else {
687 Self {
688 a: self.a.round_ties_even(),
689 b: self.b.round_ties_even(),
690 }
691 }
692 }
693 }
694
695 #[inline]
696 pub fn trunc(self) -> Self {
697 pick! {
698 if #[cfg(target_feature="avx512f")] {
699 Self { avx512: round_m512d::<{round_op!(Zero)}>(self.avx512) }
700 } else {
701 Self {
702 a: self.a.trunc(),
703 b: self.b.trunc(),
704 }
705 }
706 }
707 }
708
709 #[inline]
710 pub fn trunc_int(self) -> i64x8 {
711 pick! {
712 if #[cfg(target_feature="avx512dq")] {
713 #[cfg(target_arch = "x86")]
714 use core::arch::x86::_mm512_cvttpd_epi64;
715 #[cfg(target_arch = "x86_64")]
716 use core::arch::x86_64::_mm512_cvttpd_epi64;
717
718 let non_nan_mask = self.simd_eq(self);
720 let non_nan = self & non_nan_mask;
721 let flip_to_max: i64x8 = cast(self.simd_ge(Self::splat(9223372036854775808.0)));
722
723 let cast: i64x8 = cast(m512i(unsafe { _mm512_cvttpd_epi64(non_nan.avx512.0) }));
725 flip_to_max ^ cast
726 } else {
727 let [a,b]: [f64x4;2] = cast(self);
728 cast([
729 a.trunc_int(),
730 b.trunc_int(),
731 ])
732 }
733 }
734 }
735
736 #[inline]
737 pub fn fast_trunc_int(self) -> i64x8 {
738 pick! {
739 if #[cfg(target_feature="avx512dq")] {
740 #[cfg(target_arch = "x86")]
741 use core::arch::x86::_mm512_cvttpd_epi64;
742 #[cfg(target_arch = "x86_64")]
743 use core::arch::x86_64::_mm512_cvttpd_epi64;
744
745 cast(m512i(unsafe { _mm512_cvttpd_epi64(self.avx512.0) }))
747 } else {
748 let [a,b]: [f64x4;2] = cast(self);
749 cast([
750 a.fast_trunc_int(),
751 b.fast_trunc_int(),
752 ])
753 }
754 }
755 }
756
757 #[inline]
766 pub fn mul_add(self, a: Self, b: Self) -> Self {
767 pick! {
768 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
769 Self { avx512: fused_mul_add_m512d(self.avx512, a.avx512, b.avx512) }
770 } else if #[cfg(target_feature="avx512f")] {
771 (self * a) + b
773 } else {
774 Self {
775 a : self.a.mul_add(a.a, b.a),
776 b : self.b.mul_add(a.b, b.b),
777 }
778 }
779 }
780 }
781
782 #[inline]
791 pub fn mul_sub(self, a: Self, b: Self) -> Self {
792 pick! {
793 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
794 Self { avx512: fused_mul_sub_m512d(self.avx512, a.avx512, b.avx512) }
795 } else if #[cfg(target_feature="avx512f")] {
796 (self * a) - b
798 } else {
799 Self {
800 a : self.a.mul_sub(a.a, b.a),
801 b : self.b.mul_sub(a.b, b.b),
802 }
803 }
804 }
805 }
806
807 #[inline]
816 pub fn mul_neg_add(self, a: Self, b: Self) -> Self {
817 pick! {
818 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
819 Self { avx512: fused_mul_neg_add_m512d(self.avx512, a.avx512, b.avx512) }
820 } else if #[cfg(target_feature="avx512f")] {
821 b - (self * a)
823 } else {
824 Self {
825 a : self.a.mul_neg_add(a.a, b.a),
826 b : self.b.mul_neg_add(a.b, b.b),
827 }
828 }
829 }
830 }
831
832 #[inline]
841 pub fn mul_neg_sub(self, a: Self, b: Self) -> Self {
842 pick! {
843 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
844 Self { avx512: fused_mul_neg_sub_m512d(self.avx512, a.avx512, b.avx512) }
845 } else if #[cfg(target_feature="avx512f")] {
846 -(self * a) - b
848 } else {
849 Self {
850 a : self.a.mul_neg_sub(a.a, b.a),
851 b : self.b.mul_neg_sub(a.b, b.b),
852 }
853 }
854 }
855 }
856
857 #[inline]
858 pub fn powf_simd(self, n: Self) -> Self {
859 const_f64_as_f64x8!(ln2d_hi, 0.693145751953125);
860 const_f64_as_f64x8!(ln2d_lo, 1.42860682030941723212E-6);
861 const_f64_as_f64x8!(P0log, 2.0039553499201281259648E1);
862 const_f64_as_f64x8!(P1log, 5.7112963590585538103336E1);
863 const_f64_as_f64x8!(P2log, 6.0949667980987787057556E1);
864 const_f64_as_f64x8!(P3log, 2.9911919328553073277375E1);
865 const_f64_as_f64x8!(P4log, 6.5787325942061044846969E0);
866 const_f64_as_f64x8!(P5log, 4.9854102823193375972212E-1);
867 const_f64_as_f64x8!(P6log, 4.5270000862445199635215E-5);
868 const_f64_as_f64x8!(Q0log, 6.0118660497603843919306E1);
869 const_f64_as_f64x8!(Q1log, 2.1642788614495947685003E2);
870 const_f64_as_f64x8!(Q2log, 3.0909872225312059774938E2);
871 const_f64_as_f64x8!(Q3log, 2.2176239823732856465394E2);
872 const_f64_as_f64x8!(Q4log, 8.3047565967967209469434E1);
873 const_f64_as_f64x8!(Q5log, 1.5062909083469192043167E1);
874
875 const_f64_as_f64x8!(p2, 1.0 / 2.0); const_f64_as_f64x8!(p3, 1.0 / 6.0);
878 const_f64_as_f64x8!(p4, 1.0 / 24.0);
879 const_f64_as_f64x8!(p5, 1.0 / 120.0);
880 const_f64_as_f64x8!(p6, 1.0 / 720.0);
881 const_f64_as_f64x8!(p7, 1.0 / 5040.0);
882 const_f64_as_f64x8!(p8, 1.0 / 40320.0);
883 const_f64_as_f64x8!(p9, 1.0 / 362880.0);
884 const_f64_as_f64x8!(p10, 1.0 / 3628800.0);
885 const_f64_as_f64x8!(p11, 1.0 / 39916800.0);
886 const_f64_as_f64x8!(p12, 1.0 / 479001600.0);
887 const_f64_as_f64x8!(p13, 1.0 / 6227020800.0);
888
889 let x1 = self.abs();
890 let x = x1.fraction_2();
891 let mask = x.simd_gt(f64x8::SQRT_2 * f64x8::HALF);
892 let x = (!mask).select(x + x, x);
893 let x = x - f64x8::ONE;
894 let x2 = x * x;
895 let px = polynomial_6!(x, P0log, P1log, P2log, P3log, P4log, P5log, P6log);
896 let px = px * x * x2;
897 let qx = polynomial_6n!(x, Q0log, Q1log, Q2log, Q3log, Q4log, Q5log);
898 let lg1 = px / qx;
899
900 let ef = x1.exponent();
901 let ef = mask.select(ef + f64x8::ONE, ef);
902 let e1 = (ef * n).round_ties_even();
903 let yr = ef.mul_sub(n, e1);
904
905 let lg = f64x8::HALF.mul_neg_add(x2, x) + lg1;
906 let x2err = (f64x8::HALF * x).mul_sub(x, f64x8::HALF * x2);
907 let lg_err = f64x8::HALF.mul_add(x2, lg - x) - lg1;
908
909 let e2 = (lg * n * f64x8::LOG2_E).round_ties_even();
910 let v = lg.mul_sub(n, e2 * ln2d_hi);
911 let v = e2.mul_neg_add(ln2d_lo, v);
912 let v = v - (lg_err + x2err).mul_sub(n, yr * f64x8::LN_2);
913
914 let x = v;
915 let e3 = (x * f64x8::LOG2_E).round_ties_even();
916 let x = e3.mul_neg_add(f64x8::LN_2, x);
917 let z =
918 polynomial_13!(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)
919 + f64x8::ONE;
920 let ee = e1 + e2 + e3;
921 let ei = cast::<_, i64x8>(ee.round_int());
922 let ej = cast::<_, i64x8>(ei + (cast::<_, i64x8>(z) >> 52));
923
924 let overflow = cast::<_, f64x8>(!ej.simd_lt(i64x8::splat(0x07FF)))
925 | ee.simd_gt(f64x8::splat(3000.0));
926 let underflow = cast::<_, f64x8>(!ej.simd_gt(i64x8::splat(0x000)))
927 | ee.simd_lt(f64x8::splat(-3000.0));
928
929 let z = cast::<_, f64x8>(cast::<_, i64x8>(z) + (ei << 52));
931
932 let z = if (overflow | underflow).any() {
934 let z = underflow.select(f64x8::ZERO, z);
935 overflow.select(Self::infinity(), z)
936 } else {
937 z
938 };
939
940 let x_zero = self.is_zero_or_subnormal();
942 let z = x_zero.select(
943 n.simd_lt(f64x8::ZERO).select(
944 Self::infinity(),
945 n.simd_eq(f64x8::ZERO).select(f64x8::ONE, f64x8::ZERO),
946 ),
947 z,
948 );
949
950 let x_sign = self.is_sign_negative();
951
952 let z = if x_sign.any() {
953 let yi = n.simd_eq(n.round_ties_even());
955 let y_odd = cast::<i64x8, f64x8>(n.round_int() << 63);
957
958 let z1 = yi
959 .select(z | y_odd, self.simd_eq(Self::ZERO).select(z, Self::nan_pow()));
960 x_sign.select(z1, z)
961 } else {
962 z
963 };
964
965 let x_finite = self.is_finite();
966 let y_finite = n.is_finite();
967 let e_finite = ee.is_finite();
968
969 if (x_finite & y_finite & (e_finite | x_zero)).all() {
970 return z;
971 }
972
973 (self.is_nan() | n.is_nan()).select(self + n, z)
974 }
975
976 #[inline]
977 pub fn sqrt(self) -> Self {
978 pick! {
979 if #[cfg(target_feature="avx512f")] {
980 Self { avx512: sqrt_m512d(self.avx512) }
981 } else {
982 Self {
983 a : self.a.sqrt(),
984 b : self.b.sqrt(),
985 }
986 }
987 }
988 }
989
990 #[inline]
992 pub fn exp(self) -> Self {
993 const_f64_as_f64x8!(P2, 1.0 / 2.0);
994 const_f64_as_f64x8!(P3, 1.0 / 6.0);
995 const_f64_as_f64x8!(P4, 1.0 / 24.0);
996 const_f64_as_f64x8!(P5, 1.0 / 120.0);
997 const_f64_as_f64x8!(P6, 1.0 / 720.0);
998 const_f64_as_f64x8!(P7, 1.0 / 5040.0);
999 const_f64_as_f64x8!(P8, 1.0 / 40320.0);
1000 const_f64_as_f64x8!(P9, 1.0 / 362880.0);
1001 const_f64_as_f64x8!(P10, 1.0 / 3628800.0);
1002 const_f64_as_f64x8!(P11, 1.0 / 39916800.0);
1003 const_f64_as_f64x8!(P12, 1.0 / 479001600.0);
1004 const_f64_as_f64x8!(P13, 1.0 / 6227020800.0);
1005 const_f64_as_f64x8!(LN2D_HI, 0.693145751953125);
1009 const_f64_as_f64x8!(LN2D_LO, 1.42860682030941723212E-6);
1010 let max_x = f64x8::from(709.783);
1011 let min_x = f64x8::from(-744.79);
1012 let finite = self.is_finite();
1013 let neg_underflow = self.simd_lt(min_x) & finite;
1015 if neg_underflow.all() {
1016 return Self::ZERO;
1017 }
1018 let max_r = f64x8::from(1023.0);
1019 let r = (self * Self::LOG2_E).round_ties_even();
1020 let big = r.simd_gt(max_r);
1021 let r_safe = big.select(max_r, r);
1022 let excess = r - max_r;
1023 let excess = big.select(excess, Self::ZERO);
1024 let scale = Self::vm_pow2n(excess);
1025 let x = r.mul_neg_add(LN2D_HI, self);
1026 let x = r.mul_neg_add(LN2D_LO, x);
1027 let z =
1028 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1029 let n2 = Self::vm_pow2n(r_safe);
1030 let z = (z + Self::ONE) * scale * n2;
1031 let nan_mask = self.is_nan();
1032 let mut result = nan_mask.select(Self::nan_pow(), z);
1033 let pos_overflow = self.simd_gt(max_x) & finite;
1034 result = pos_overflow.select(Self::infinity(), result);
1035 result = neg_underflow.select(Self::ZERO, result);
1036 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1037 result = pos_inf.select(Self::infinity(), result);
1038 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1039 result = neg_inf.select(Self::ZERO, result);
1040 result
1041 }
1042
1043 #[inline]
1044 pub fn exp2(self) -> Self {
1045 const_f64_as_f64x8!(P2, 1.0 / 2.0);
1046 const_f64_as_f64x8!(P3, 1.0 / 6.0);
1047 const_f64_as_f64x8!(P4, 1.0 / 24.0);
1048 const_f64_as_f64x8!(P5, 1.0 / 120.0);
1049 const_f64_as_f64x8!(P6, 1.0 / 720.0);
1050 const_f64_as_f64x8!(P7, 1.0 / 5040.0);
1051 const_f64_as_f64x8!(P8, 1.0 / 40320.0);
1052 const_f64_as_f64x8!(P9, 1.0 / 362880.0);
1053 const_f64_as_f64x8!(P10, 1.0 / 3628800.0);
1054
1055 let max_x = f64x8::from(1023.9999999999999);
1058 let min_x = f64x8::from(-1074.5);
1059 let finite = self.is_finite();
1060 let neg_underflow = self.simd_lt(min_x) & finite;
1061 if neg_underflow.all() {
1062 return Self::ZERO;
1063 }
1064
1065 let round = self.round_ties_even();
1066 let max_r = f64x8::from(1023.0);
1067 let big = round.simd_gt(max_r);
1068 let r_safe = big.select(max_r, round);
1069 let excess = round - max_r;
1070 let excess = big.select(excess, Self::ZERO);
1071 let scale = Self::vm_pow2n(excess);
1072
1073 let fract = (self - round) * Self::LN_2;
1074 let fract_partial_exp2 =
1075 polynomial_8!(fract, P2, P3, P4, P5, P6, P7, P8, P9, P10);
1076 let fract2 = fract * fract;
1077 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1078
1079 let n2 = Self::vm_pow2n(r_safe);
1080 let result = fract_exp2 * scale * n2;
1081
1082 let nan_mask = self.is_nan();
1083 let mut result = nan_mask.select(Self::nan_pow(), result);
1084 let pos_overflow = self.simd_gt(max_x) & finite;
1085 result = pos_overflow.select(Self::infinity(), result);
1086 result = neg_underflow.select(Self::ZERO, result);
1087 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1088 result = pos_inf.select(Self::infinity(), result);
1089 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1090 result = neg_inf.select(Self::ZERO, result);
1091 result
1092 }
1093
1094 #[inline]
1095 pub fn ln(self) -> Self {
1096 const_f64_as_f64x8!(HALF, 0.5);
1097 const_f64_as_f64x8!(P0, 7.70838733755885391666E0);
1098 const_f64_as_f64x8!(P1, 1.79368678507819816313E1);
1099 const_f64_as_f64x8!(P2, 1.44989225341610930846E1);
1100 const_f64_as_f64x8!(P3, 4.70579119878881725854E0);
1101 const_f64_as_f64x8!(P4, 4.97494994976747001425E-1);
1102 const_f64_as_f64x8!(P5, 1.01875663804580931796E-4);
1103
1104 const_f64_as_f64x8!(Q0, 2.31251620126765340583E1);
1105 const_f64_as_f64x8!(Q1, 7.11544750618563894466E1);
1106 const_f64_as_f64x8!(Q2, 8.29875266912776603211E1);
1107 const_f64_as_f64x8!(Q3, 4.52279145837532221105E1);
1108 const_f64_as_f64x8!(Q4, 1.12873587189167450590E1);
1109 const_f64_as_f64x8!(LN2F_HI, f64::from_bits(0x3FE62E42FEE00000));
1115 const_f64_as_f64x8!(LN2F_LO, f64::from_bits(0x3DEA39EF35793C76));
1116 const_f64_as_f64x8!(VM_SQRT2, 1.414213562373095048801);
1117 const_f64_as_f64x8!(VM_SMALLEST_NORMAL, 2.2250738585072014E-308);
1118
1119 let x1 = self;
1120 let x = Self::fraction_2(x1);
1121 let e = Self::exponent(x1);
1122 let mask = x.simd_gt(VM_SQRT2 * HALF);
1123 let x = (!mask).select(x + x, x);
1124 let fe = mask.select(e + Self::ONE, e);
1125 let x = x - Self::ONE;
1126 let px = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1127 let x2 = x * x;
1128 let px = x2 * x * px;
1129 let qx = polynomial_5n!(x, Q0, Q1, Q2, Q3, Q4);
1130 let res = px / qx;
1131 let res = fe.mul_add(LN2F_LO, res);
1132 let res = res + x2.mul_neg_add(HALF, x);
1133 let res = fe.mul_add(LN2F_HI, res);
1134 let overflow = !self.is_finite();
1135 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1136 let mask = overflow | underflow;
1137 if !mask.any() {
1138 res
1139 } else {
1140 let is_zero = self.is_zero_or_subnormal();
1141 let res = underflow.select(Self::nan_log(), res);
1142 let res = is_zero.select(-Self::infinity(), res);
1147 let res = overflow.select(self, res);
1148 let res = (!self.is_finite() & self.is_sign_negative())
1150 .select(Self::nan_log(), res);
1151 res
1152 }
1153 }
1154
1155 #[inline]
1156 pub fn cbrt(self) -> Self {
1157 let a = self.abs();
1158 let zero = a.simd_eq(Self::ZERO);
1159 if zero.all() {
1160 return self; }
1162 let inf = a.is_inf();
1163 let nan = self.is_nan();
1164
1165 const SUBN_SCALE: f64 = 1.8014398509481984e16;
1166 const SUBN_CBRT: f64 = 262144.0;
1167 let tiny = a.simd_lt(Self::from(f64::MIN_POSITIVE));
1168 let a = tiny.select(a * Self::from(SUBN_SCALE), a);
1169
1170 let e = Self::exponent(a) + Self::ONE;
1171 let d = Self::fraction_2(a);
1172
1173 const_f64_as_f64x8!(C0, 2.2307275302496609725722);
1178 const_f64_as_f64x8!(C1, -3.85841935510444988821632);
1179 const_f64_as_f64x8!(C2, 6.03990368989458747961407);
1180 const_f64_as_f64x8!(C3, -5.73353060922947843636166);
1181 const_f64_as_f64x8!(C4, 2.96155103020039511818595);
1182 const_f64_as_f64x8!(C5, -0.640245898480692909870982);
1183 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1184
1185 let x2 = x * x;
1187 let x4 = x2 * x2;
1188 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1189
1190 let mut y = (d * x) * x;
1192 let yx = y * x;
1193 let t = Self::from(2.0 / 3.0);
1194 y = y - t * y * (yx - Self::ONE);
1195
1196 let three = Self::from(3.0);
1198 let two = Self::from(2.0);
1199 let neg = e.simd_lt(Self::ZERO);
1200 let e_adj = neg.select(e - two, e);
1201 let k = (e_adj / three).trunc();
1202 let r = e - three * k;
1203 const_f64_as_f64x8!(CBRT2, 1.2599210498948732);
1204 const_f64_as_f64x8!(CBRT4, 1.5874010519681994);
1205 y = r.simd_eq(Self::ONE).select(y * CBRT2, y);
1206 y = r.simd_eq(two).select(y * CBRT4, y);
1207 y *= Self::vm_pow2n(k);
1208 y = tiny.select(y / Self::from(SUBN_CBRT), y);
1209
1210 let result = y.flip_signs(self);
1211 let result = nan.select(self, result);
1212 let result = zero.select(self, result);
1213 let result = inf.select(self, result);
1214 result
1215 }
1216
1217 #[inline]
1218 pub fn asin(self) -> Self {
1219 const_f64_as_f64x8!(R4asin, 2.967721961301243206100E-3);
1222 const_f64_as_f64x8!(R3asin, -5.634242780008963776856E-1);
1223 const_f64_as_f64x8!(R2asin, 6.968710824104713396794E0);
1224 const_f64_as_f64x8!(R1asin, -2.556901049652824852289E1);
1225 const_f64_as_f64x8!(R0asin, 2.853665548261061424989E1);
1226
1227 const_f64_as_f64x8!(S3asin, -2.194779531642920639778E1);
1228 const_f64_as_f64x8!(S2asin, 1.470656354026814941758E2);
1229 const_f64_as_f64x8!(S1asin, -3.838770957603691357202E2);
1230 const_f64_as_f64x8!(S0asin, 3.424398657913078477438E2);
1231
1232 const_f64_as_f64x8!(P5asin, 4.253011369004428248960E-3);
1233 const_f64_as_f64x8!(P4asin, -6.019598008014123785661E-1);
1234 const_f64_as_f64x8!(P3asin, 5.444622390564711410273E0);
1235 const_f64_as_f64x8!(P2asin, -1.626247967210700244449E1);
1236 const_f64_as_f64x8!(P1asin, 1.956261983317594739197E1);
1237 const_f64_as_f64x8!(P0asin, -8.198089802484824371615E0);
1238
1239 const_f64_as_f64x8!(Q4asin, -1.474091372988853791896E1);
1240 const_f64_as_f64x8!(Q3asin, 7.049610280856842141659E1);
1241 const_f64_as_f64x8!(Q2asin, -1.471791292232726029859E2);
1242 const_f64_as_f64x8!(Q1asin, 1.395105614657485689735E2);
1243 const_f64_as_f64x8!(Q0asin, -4.918853881490881290097E1);
1244
1245 let xa = self.abs();
1246
1247 let big = xa.simd_ge(f64x8::splat(0.625));
1248
1249 let x1 = big.select(f64x8::splat(1.0) - xa, xa * xa);
1250
1251 let x2 = x1 * x1;
1252 let x3 = x2 * x1;
1253 let x4 = x2 * x2;
1254 let x5 = x4 * x1;
1255
1256 let do_big = big.any();
1257 let do_small = !big.all();
1258
1259 let mut rx = f64x8::default();
1260 let mut sx = f64x8::default();
1261 let mut px = f64x8::default();
1262 let mut qx = f64x8::default();
1263
1264 if do_big {
1265 rx = x3.mul_add(R3asin, x2 * R2asin)
1266 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1267 sx =
1268 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1269 }
1270 if do_small {
1271 px = x3.mul_add(P3asin, P0asin)
1272 + x4.mul_add(P4asin, x1 * P1asin)
1273 + x5.mul_add(P5asin, x2 * P2asin);
1274 qx = x4.mul_add(Q4asin, x5)
1275 + x3.mul_add(Q3asin, x1 * Q1asin)
1276 + x2.mul_add(Q2asin, Q0asin);
1277 };
1278
1279 let vx = big.select(rx, px);
1280 let wx = big.select(sx, qx);
1281
1282 let y1 = vx / wx * x1;
1283
1284 let mut z1 = f64x8::default();
1285 let mut z2 = f64x8::default();
1286 if do_big {
1287 let xb = (x1 + x1).sqrt();
1288 z1 = xb.mul_add(y1, xb);
1289 }
1290
1291 if do_small {
1292 z2 = xa.mul_add(y1, xa);
1293 }
1294
1295 let z3 = f64x8::FRAC_PI_2 - z1;
1297 let asin = big.select(z3, z2);
1298 let asin = asin.flip_signs(self);
1299
1300 asin
1301 }
1302
1303 #[inline]
1304 pub fn acos(self) -> Self {
1305 const_f64_as_f64x8!(R4asin, 2.967721961301243206100E-3);
1308 const_f64_as_f64x8!(R3asin, -5.634242780008963776856E-1);
1309 const_f64_as_f64x8!(R2asin, 6.968710824104713396794E0);
1310 const_f64_as_f64x8!(R1asin, -2.556901049652824852289E1);
1311 const_f64_as_f64x8!(R0asin, 2.853665548261061424989E1);
1312
1313 const_f64_as_f64x8!(S3asin, -2.194779531642920639778E1);
1314 const_f64_as_f64x8!(S2asin, 1.470656354026814941758E2);
1315 const_f64_as_f64x8!(S1asin, -3.838770957603691357202E2);
1316 const_f64_as_f64x8!(S0asin, 3.424398657913078477438E2);
1317
1318 const_f64_as_f64x8!(P5asin, 4.253011369004428248960E-3);
1319 const_f64_as_f64x8!(P4asin, -6.019598008014123785661E-1);
1320 const_f64_as_f64x8!(P3asin, 5.444622390564711410273E0);
1321 const_f64_as_f64x8!(P2asin, -1.626247967210700244449E1);
1322 const_f64_as_f64x8!(P1asin, 1.956261983317594739197E1);
1323 const_f64_as_f64x8!(P0asin, -8.198089802484824371615E0);
1324
1325 const_f64_as_f64x8!(Q4asin, -1.474091372988853791896E1);
1326 const_f64_as_f64x8!(Q3asin, 7.049610280856842141659E1);
1327 const_f64_as_f64x8!(Q2asin, -1.471791292232726029859E2);
1328 const_f64_as_f64x8!(Q1asin, 1.395105614657485689735E2);
1329 const_f64_as_f64x8!(Q0asin, -4.918853881490881290097E1);
1330
1331 let xa = self.abs();
1332
1333 let big = xa.simd_ge(f64x8::splat(0.625));
1334
1335 let x1 = big.select(f64x8::splat(1.0) - xa, xa * xa);
1336
1337 let x2 = x1 * x1;
1338 let x3 = x2 * x1;
1339 let x4 = x2 * x2;
1340 let x5 = x4 * x1;
1341
1342 let do_big = big.any();
1343 let do_small = !big.all();
1344
1345 let mut rx = f64x8::default();
1346 let mut sx = f64x8::default();
1347 let mut px = f64x8::default();
1348 let mut qx = f64x8::default();
1349
1350 if do_big {
1351 rx = x3.mul_add(R3asin, x2 * R2asin)
1352 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1353 sx =
1354 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1355 }
1356 if do_small {
1357 px = x3.mul_add(P3asin, P0asin)
1358 + x4.mul_add(P4asin, x1 * P1asin)
1359 + x5.mul_add(P5asin, x2 * P2asin);
1360 qx = x4.mul_add(Q4asin, x5)
1361 + x3.mul_add(Q3asin, x1 * Q1asin)
1362 + x2.mul_add(Q2asin, Q0asin);
1363 };
1364
1365 let vx = big.select(rx, px);
1366 let wx = big.select(sx, qx);
1367
1368 let y1 = vx / wx * x1;
1369
1370 let mut z1 = f64x8::default();
1371 let mut z2 = f64x8::default();
1372 if do_big {
1373 let xb = (x1 + x1).sqrt();
1374 z1 = xb.mul_add(y1, xb);
1375 }
1376
1377 if do_small {
1378 z2 = xa.mul_add(y1, xa);
1379 }
1380
1381 let z3 = self.simd_lt(f64x8::ZERO).select(f64x8::PI - z1, z1);
1383 let z4 = f64x8::FRAC_PI_2 - z2.flip_signs(self);
1384 let acos = big.select(z3, z4);
1385
1386 acos
1387 }
1388
1389 #[inline]
1390 pub fn atan(self) -> Self {
1391 const_f64_as_f64x8!(MORE_BITS, 6.123233995736765886130E-17);
1394 const_f64_as_f64x8!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1395 const_f64_as_f64x8!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1396
1397 const_f64_as_f64x8!(P4atan, -8.750608600031904122785E-1);
1398 const_f64_as_f64x8!(P3atan, -1.615753718733365076637E1);
1399 const_f64_as_f64x8!(P2atan, -7.500855792314704667340E1);
1400 const_f64_as_f64x8!(P1atan, -1.228866684490136173410E2);
1401 const_f64_as_f64x8!(P0atan, -6.485021904942025371773E1);
1402
1403 const_f64_as_f64x8!(Q4atan, 2.485846490142306297962E1);
1404 const_f64_as_f64x8!(Q3atan, 1.650270098316988542046E2);
1405 const_f64_as_f64x8!(Q2atan, 4.328810604912902668951E2);
1406 const_f64_as_f64x8!(Q1atan, 4.853903996359136964868E2);
1407 const_f64_as_f64x8!(Q0atan, 1.945506571482613964425E2);
1408
1409 let t = self.abs();
1410
1411 let notbig = t.simd_le(T3PO8);
1415 let notsmal = t.simd_ge(Self::splat(0.66));
1416
1417 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1418 s = notsmal & s;
1419 let mut fac = notbig.select(MORE_BITS_O2, MORE_BITS);
1420 fac = notsmal & fac;
1421
1422 let mut a = notbig & t;
1426 a = notsmal.select(a - Self::ONE, a);
1427 let mut b = notbig & Self::ONE;
1428 b = notsmal.select(b + t, b);
1429 let z = a / b;
1430
1431 let zz = z * z;
1432
1433 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1434 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1435
1436 let mut re = (px / qx).mul_add(z * zz, z);
1437 re += s + fac;
1438
1439 re = (self.is_sign_negative()).select(-re, re);
1441
1442 re
1443 }
1444
1445 #[inline]
1446 pub fn atan2(self, x: Self) -> Self {
1447 const_f64_as_f64x8!(MORE_BITS, 6.123233995736765886130E-17);
1450 const_f64_as_f64x8!(MORE_BITS_O2, 6.123233995736765886130E-17 * 0.5);
1451 const_f64_as_f64x8!(T3PO8, core::f64::consts::SQRT_2 + 1.0);
1452
1453 const_f64_as_f64x8!(P4atan, -8.750608600031904122785E-1);
1454 const_f64_as_f64x8!(P3atan, -1.615753718733365076637E1);
1455 const_f64_as_f64x8!(P2atan, -7.500855792314704667340E1);
1456 const_f64_as_f64x8!(P1atan, -1.228866684490136173410E2);
1457 const_f64_as_f64x8!(P0atan, -6.485021904942025371773E1);
1458
1459 const_f64_as_f64x8!(Q4atan, 2.485846490142306297962E1);
1460 const_f64_as_f64x8!(Q3atan, 1.650270098316988542046E2);
1461 const_f64_as_f64x8!(Q2atan, 4.328810604912902668951E2);
1462 const_f64_as_f64x8!(Q1atan, 4.853903996359136964868E2);
1463 const_f64_as_f64x8!(Q0atan, 1.945506571482613964425E2);
1464
1465 let y = self;
1466
1467 let x1 = x.abs();
1469 let y1 = y.abs();
1470 let swapxy = y1.simd_gt(x1);
1471 let mut x2 = swapxy.select(y1, x1);
1473 let mut y2 = swapxy.select(x1, y1);
1474
1475 let both_infinite = x.is_inf() & y.is_inf();
1477 if both_infinite.any() {
1478 let minus_one = -Self::ONE;
1479 x2 = both_infinite.select(x2 & minus_one, x2);
1480 y2 = both_infinite.select(y2 & minus_one, y2);
1481 }
1482
1483 let t = y2 / x2;
1485
1486 let notbig = t.simd_le(T3PO8);
1490 let notsmal = t.simd_ge(Self::splat(0.66));
1491
1492 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1493 s = notsmal & s;
1494 let mut fac = notbig.select(MORE_BITS_O2, MORE_BITS);
1495 fac = notsmal & fac;
1496
1497 let mut a = notbig & t;
1501 a = notsmal.select(a - Self::ONE, a);
1502 let mut b = notbig & Self::ONE;
1503 b = notsmal.select(b + t, b);
1504 let z = a / b;
1505
1506 let zz = z * z;
1507
1508 let px = polynomial_4!(zz, P0atan, P1atan, P2atan, P3atan, P4atan);
1509 let qx = polynomial_5n!(zz, Q0atan, Q1atan, Q2atan, Q3atan, Q4atan);
1510
1511 let mut re = (px / qx).mul_add(z * zz, z);
1512 re += s + fac;
1513
1514 re = swapxy.select(Self::FRAC_PI_2 - re, re);
1516 re = ((x | y).simd_eq(Self::ZERO)).select(Self::ZERO, re);
1517 re = (x.is_sign_negative()).select(Self::PI - re, re);
1518
1519 re = (y.is_sign_negative()).select(-re, re);
1521
1522 re
1523 }
1524
1525 #[inline]
1526 pub fn sin_cos(self) -> (Self, Self) {
1527 const_f64_as_f64x8!(P0sin, -1.66666666666666307295E-1);
1531 const_f64_as_f64x8!(P1sin, 8.33333333332211858878E-3);
1532 const_f64_as_f64x8!(P2sin, -1.98412698295895385996E-4);
1533 const_f64_as_f64x8!(P3sin, 2.75573136213857245213E-6);
1534 const_f64_as_f64x8!(P4sin, -2.50507477628578072866E-8);
1535 const_f64_as_f64x8!(P5sin, 1.58962301576546568060E-10);
1536
1537 const_f64_as_f64x8!(P0cos, 4.16666666666665929218E-2);
1538 const_f64_as_f64x8!(P1cos, -1.38888888888730564116E-3);
1539 const_f64_as_f64x8!(P2cos, 2.48015872888517045348E-5);
1540 const_f64_as_f64x8!(P3cos, -2.75573141792967388112E-7);
1541 const_f64_as_f64x8!(P4cos, 2.08757008419747316778E-9);
1542 const_f64_as_f64x8!(P5cos, -1.13585365213876817300E-11);
1543
1544 const_f64_as_f64x8!(DP1, 7.853981554508209228515625E-1 * 2.);
1545 const_f64_as_f64x8!(DP2, 7.94662735614792836714E-9 * 2.);
1546 const_f64_as_f64x8!(DP3, 3.06161699786838294307E-17 * 2.);
1547
1548 const_f64_as_f64x8!(TWO_OVER_PI, 2.0 / core::f64::consts::PI);
1549
1550 let xa = self.abs();
1551
1552 let y = (xa * TWO_OVER_PI).round_ties_even();
1553 let q = y.round_int();
1554
1555 let x = y.mul_neg_add(DP3, y.mul_neg_add(DP2, y.mul_neg_add(DP1, xa)));
1556
1557 let x2 = x * x;
1558 let mut s = polynomial_5!(x2, P0sin, P1sin, P2sin, P3sin, P4sin, P5sin);
1559 let mut c = polynomial_5!(x2, P0cos, P1cos, P2cos, P3cos, P4cos, P5cos);
1560 s = (x * x2).mul_add(s, x);
1561 c =
1562 (x2 * x2).mul_add(c, x2.mul_neg_add(f64x8::from(0.5), f64x8::from(1.0)));
1563
1564 let swap = !((q & i64x8::from(1)).simd_eq(i64x8::from(0)));
1565
1566 let mut overflow: f64x8 = cast(q.simd_gt(i64x8::from(0x80000000000000)));
1567 overflow &= xa.is_finite();
1568 s = overflow.select(f64x8::from(0.0), s);
1569 c = overflow.select(f64x8::from(1.0), c);
1570
1571 let mut sin1 = cast::<_, f64x8>(swap).select(c, s);
1573 let sign_sin: i64x8 = (q << 62) ^ cast::<_, i64x8>(self);
1574 sin1 = sin1.flip_signs(cast(sign_sin));
1575
1576 let mut cos1 = cast::<_, f64x8>(swap).select(s, c);
1578 let sign_cos: i64x8 = ((q + i64x8::from(1)) & i64x8::from(2)) << 62;
1579 cos1 ^= cast::<_, f64x8>(sign_cos);
1580
1581 let finite = self.is_finite();
1583 let nan = Self::splat(f64::NAN);
1584 let sin_final = finite.select(sin1, nan);
1585 let cos_final = finite.select(cos1, nan);
1586
1587 (sin_final, cos_final)
1588 }
1589
1590 #[inline]
1591 pub fn asin_acos(self) -> (Self, Self) {
1592 const_f64_as_f64x8!(R4asin, 2.967721961301243206100E-3);
1595 const_f64_as_f64x8!(R3asin, -5.634242780008963776856E-1);
1596 const_f64_as_f64x8!(R2asin, 6.968710824104713396794E0);
1597 const_f64_as_f64x8!(R1asin, -2.556901049652824852289E1);
1598 const_f64_as_f64x8!(R0asin, 2.853665548261061424989E1);
1599
1600 const_f64_as_f64x8!(S3asin, -2.194779531642920639778E1);
1601 const_f64_as_f64x8!(S2asin, 1.470656354026814941758E2);
1602 const_f64_as_f64x8!(S1asin, -3.838770957603691357202E2);
1603 const_f64_as_f64x8!(S0asin, 3.424398657913078477438E2);
1604
1605 const_f64_as_f64x8!(P5asin, 4.253011369004428248960E-3);
1606 const_f64_as_f64x8!(P4asin, -6.019598008014123785661E-1);
1607 const_f64_as_f64x8!(P3asin, 5.444622390564711410273E0);
1608 const_f64_as_f64x8!(P2asin, -1.626247967210700244449E1);
1609 const_f64_as_f64x8!(P1asin, 1.956261983317594739197E1);
1610 const_f64_as_f64x8!(P0asin, -8.198089802484824371615E0);
1611
1612 const_f64_as_f64x8!(Q4asin, -1.474091372988853791896E1);
1613 const_f64_as_f64x8!(Q3asin, 7.049610280856842141659E1);
1614 const_f64_as_f64x8!(Q2asin, -1.471791292232726029859E2);
1615 const_f64_as_f64x8!(Q1asin, 1.395105614657485689735E2);
1616 const_f64_as_f64x8!(Q0asin, -4.918853881490881290097E1);
1617
1618 let xa = self.abs();
1619
1620 let big = xa.simd_ge(f64x8::splat(0.625));
1621
1622 let x1 = big.select(f64x8::splat(1.0) - xa, xa * xa);
1623
1624 let x2 = x1 * x1;
1625 let x3 = x2 * x1;
1626 let x4 = x2 * x2;
1627 let x5 = x4 * x1;
1628
1629 let do_big = big.any();
1630 let do_small = !big.all();
1631
1632 let mut rx = f64x8::default();
1633 let mut sx = f64x8::default();
1634 let mut px = f64x8::default();
1635 let mut qx = f64x8::default();
1636
1637 if do_big {
1638 rx = x3.mul_add(R3asin, x2 * R2asin)
1639 + x4.mul_add(R4asin, x1.mul_add(R1asin, R0asin));
1640 sx =
1641 x3.mul_add(S3asin, x4) + x2.mul_add(S2asin, x1.mul_add(S1asin, S0asin));
1642 }
1643
1644 if do_small {
1645 px = x3.mul_add(P3asin, P0asin)
1646 + x4.mul_add(P4asin, x1 * P1asin)
1647 + x5.mul_add(P5asin, x2 * P2asin);
1648 qx = x4.mul_add(Q4asin, x5)
1649 + x3.mul_add(Q3asin, x1 * Q1asin)
1650 + x2.mul_add(Q2asin, Q0asin);
1651 };
1652
1653 let vx = big.select(rx, px);
1654 let wx = big.select(sx, qx);
1655
1656 let y1 = vx / wx * x1;
1657
1658 let mut z1 = f64x8::default();
1659 let mut z2 = f64x8::default();
1660 if do_big {
1661 let xb = (x1 + x1).sqrt();
1662 z1 = xb.mul_add(y1, xb);
1663 }
1664
1665 if do_small {
1666 z2 = xa.mul_add(y1, xa);
1667 }
1668
1669 let z3 = f64x8::FRAC_PI_2 - z1;
1671 let asin = big.select(z3, z2);
1672 let asin = asin.flip_signs(self);
1673
1674 let z3 = self.simd_lt(f64x8::ZERO).select(f64x8::PI - z1, z1);
1676 let z4 = f64x8::FRAC_PI_2 - z2.flip_signs(self);
1677 let acos = big.select(z3, z4);
1678
1679 (asin, acos)
1680 }
1681
1682 #[inline]
1683 pub fn exp_m1(self) -> Self {
1684 const_f64_as_f64x8!(P2, 1.0 / 2.0);
1685 const_f64_as_f64x8!(P3, 1.0 / 6.0);
1686 const_f64_as_f64x8!(P4, 1.0 / 24.0);
1687 const_f64_as_f64x8!(P5, 1.0 / 120.0);
1688 const_f64_as_f64x8!(P6, 1.0 / 720.0);
1689 const_f64_as_f64x8!(P7, 1.0 / 5040.0);
1690 const_f64_as_f64x8!(P8, 1.0 / 40320.0);
1691 const_f64_as_f64x8!(P9, 1.0 / 362880.0);
1692 const_f64_as_f64x8!(P10, 1.0 / 3628800.0);
1693 const_f64_as_f64x8!(P11, 1.0 / 39916800.0);
1694 const_f64_as_f64x8!(P12, 1.0 / 479001600.0);
1695 const_f64_as_f64x8!(P13, 1.0 / 6227020800.0);
1696 const_f64_as_f64x8!(LN2D_HI, 0.693145751953125);
1699 const_f64_as_f64x8!(LN2D_LO, 1.42860682030941723212E-6);
1700 if self.simd_lt(f64x8::from(-37.429)).all() {
1704 return f64x8::from(-1.0);
1705 }
1706 let max_x = f64x8::from(709.783);
1710 let min_x = f64x8::from(-744.79);
1711 let max_r = f64x8::from(1023.0);
1712 let r = (self * Self::LOG2_E).round_ties_even();
1713 let big = r.simd_gt(max_r);
1714 let r_safe = big.select(max_r, r);
1715 let excess = r - max_r;
1716 let excess = big.select(excess, Self::ZERO);
1717 let scale = Self::vm_pow2n(excess);
1718 let x = r.mul_neg_add(LN2D_HI, self);
1719 let x = r.mul_neg_add(LN2D_LO, x);
1720 let z =
1721 polynomial_13!(x, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13);
1722 let n2 = Self::vm_pow2n(r_safe);
1723 let exp_val = (z + Self::ONE) * scale * n2;
1724 let r_is_zero = r.simd_eq(Self::ZERO);
1728 let z = r_is_zero.select(z, exp_val - Self::ONE);
1729 let nan_mask = self.is_nan();
1730 let finite = self.is_finite();
1731 let mut result = nan_mask.select(Self::nan_pow(), z);
1732 let pos_overflow = self.simd_gt(max_x) & finite;
1733 result = pos_overflow.select(Self::infinity(), result);
1734 let neg_underflow = self.simd_lt(min_x) & finite;
1735 result = neg_underflow.select(-Self::ONE, result);
1736 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1737 result = pos_inf.select(Self::infinity(), result);
1738 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1739 result = neg_inf.select(-Self::ONE, result);
1740 let is_zero = self.simd_eq(Self::ZERO);
1741 result = is_zero.select(self, result);
1742 result
1743 }
1744
1745 #[inline]
1746 pub fn ln_1p(self) -> Self {
1747 let u = self + Self::ONE;
1755 let eq = u.simd_eq(Self::ONE);
1756 let ln_u = Self::ln(u);
1757 let correction = self * (ln_u / (u - Self::ONE));
1758 let result = eq.select(self, correction);
1759 let over = u.is_inf();
1760 over.select(ln_u, result)
1761 }
1762
1763 #[inline]
1764 pub fn sinh(self) -> Self {
1765 const_f64_as_f64x8!(P0, 1.0);
1766 const_f64_as_f64x8!(P1, 1.0 / 6.0);
1767 const_f64_as_f64x8!(P2, 1.0 / 120.0);
1768 const_f64_as_f64x8!(P3, 1.0 / 5040.0);
1769 const_f64_as_f64x8!(P4, 1.0 / 362880.0);
1770 const_f64_as_f64x8!(P5, 1.0 / 39916800.0);
1771 const_f64_as_f64x8!(P6, 1.0 / 6227020800.0);
1772 let a = self.abs();
1773 let small = a.simd_lt(f64x8::from(0.5));
1775 let t = a * a;
1776 let poly = a * polynomial_6!(t, P0, P1, P2, P3, P4, P5, P6);
1777 let exp_based = {
1778 let e = a.exp();
1779 (e - Self::ONE / e) * Self::HALF
1780 };
1781 let result = small.select(poly, exp_based);
1782 result.flip_signs(self)
1783 }
1784
1785 #[inline]
1786 pub fn cosh(self) -> Self {
1787 const_f64_as_f64x8!(P0, 1.0);
1788 const_f64_as_f64x8!(P1, 1.0 / 2.0);
1789 const_f64_as_f64x8!(P2, 1.0 / 24.0);
1790 const_f64_as_f64x8!(P3, 1.0 / 720.0);
1791 const_f64_as_f64x8!(P4, 1.0 / 40320.0);
1792 const_f64_as_f64x8!(P5, 1.0 / 3628800.0);
1793 const_f64_as_f64x8!(P6, 1.0 / 479001600.0);
1794 const_f64_as_f64x8!(P7, 1.0 / 87178291200.0);
1795 let a = self.abs();
1796 let small = a.simd_lt(f64x8::from(0.5));
1798 let t = a * a;
1799 let poly = polynomial_7!(t, P0, P1, P2, P3, P4, P5, P6, P7);
1800 let exp_based = {
1801 let e = a.exp();
1802 (e + Self::ONE / e) * Self::HALF
1803 };
1804 small.select(poly, exp_based)
1805 }
1806
1807 #[inline]
1808 pub fn tanh(self) -> Self {
1809 let a = self.abs();
1813 let large = a.simd_gt(f64x8::from(19.062));
1814 if large.all() {
1815 return Self::ONE.flip_signs(self);
1816 }
1817 let small = a.simd_lt(f64x8::from(5e-8));
1818 let exp_based = {
1819 let t = (Self::from(-2.0) * a).exp_m1();
1820 let pos = -t / (t + Self::from(2.0));
1821 pos.flip_signs(self)
1822 };
1823 let result = small.select(self, exp_based);
1824 large.select(Self::ONE.flip_signs(self), result)
1825 }
1826}
1827
1828impl f64x8 {
1831 #[inline]
1832 fn vm_pow2n(self) -> Self {
1833 const_f64_as_f64x8!(pow2_52, 4503599627370496.0);
1834 const_f64_as_f64x8!(bias, 1023.0);
1835 let a = self + (bias + pow2_52);
1836 let c = cast::<_, i64x8>(a) << 52;
1837 let std_result = cast::<_, f64x8>(c);
1838
1839 let min_exp = f64x8::from(-1022.0);
1840 let is_sub = self.simd_lt(min_exp);
1841 if is_sub.any() {
1842 let valid = self.simd_ge(f64x8::from(-1074.0));
1843 let shift_f = self + f64x8::from(1074.0);
1844 let mut shift_i = shift_f.trunc_int();
1845 shift_i = cast::<_, i64x8>(valid).select(shift_i, i64x8::ZERO);
1846 let mantissa = i64x8::ONE << shift_i;
1847 let sub_result = cast::<_, f64x8>(mantissa);
1848 let sub_result = valid.select(sub_result, f64x8::ZERO);
1849 is_sub.select(sub_result, std_result)
1850 } else {
1851 std_result
1852 }
1853 }
1854
1855 #[inline]
1856 fn exponent(self) -> f64x8 {
1857 const_f64_as_f64x8!(pow2_52, 4503599627370496.0);
1858 const_f64_as_f64x8!(bias, 1023.0);
1859 let a = cast::<_, u64x8>(self);
1860 let b = a >> 52;
1861 let c = b | cast::<_, u64x8>(pow2_52);
1862 let d = cast::<_, f64x8>(c);
1863 let e = d - (pow2_52 + bias);
1864 e
1865 }
1866
1867 #[inline]
1868 fn fraction_2(self) -> Self {
1869 let t1 = cast::<_, u64x8>(self);
1870 let t2 = cast::<_, u64x8>(
1871 (t1 & u64x8::from(0x000FFFFFFFFFFFFF)) | u64x8::from(0x3FE0000000000000),
1872 );
1873 cast::<_, f64x8>(t2)
1874 }
1875 #[inline]
1876 fn is_zero_or_subnormal(self) -> Self {
1877 let t = cast::<_, i64x8>(self);
1878 let t = t & i64x8::splat(0x7FF0000000000000);
1879 let mask = t.simd_eq(i64x8::splat(0));
1880 cast::<_, f64x8>(mask)
1881 }
1882 #[inline]
1883 fn infinity() -> Self {
1884 cast::<_, f64x8>(i64x8::splat(0x7FF0000000000000))
1885 }
1886 #[inline]
1887 fn nan_log() -> Self {
1888 cast::<_, f64x8>(i64x8::splat(0x7FF8000000000000 | 0x101 << 29))
1889 }
1890 #[inline]
1891 fn nan_pow() -> Self {
1892 cast::<_, f64x8>(i64x8::splat(0x7FF8000000000000 | 0x101 << 29))
1893 }
1894
1895 #[inline]
1897 pub fn from_i32x8(v: i32x8) -> Self {
1898 pick! {
1899 if #[cfg(target_feature="avx512f")] {
1900 Self { avx512: convert_to_m512d_from_i32_m256i(v.avx2) }
1901 } else {
1902 Self::new([
1903 v.as_array()[0] as f64,
1904 v.as_array()[1] as f64,
1905 v.as_array()[2] as f64,
1906 v.as_array()[3] as f64,
1907 v.as_array()[4] as f64,
1908 v.as_array()[5] as f64,
1909 v.as_array()[6] as f64,
1910 v.as_array()[7] as f64,
1911 ])
1912 }
1913 }
1914 }
1915}
1916
1917impl From<i32x8> for f64x8 {
1918 #[inline]
1919 fn from(v: i32x8) -> Self {
1920 Self::from_i32x8(v)
1921 }
1922}