1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
6 #[repr(C, align(32))]
7 pub struct f32x8 { pub(crate) avx: m256 }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq)]
10 #[repr(C, align(32))]
11 pub struct f32x8 { pub(crate) a : f32x4, pub(crate) b : f32x4 }
12 }
13}
14
15macro_rules! const_f32_as_f32x8 {
16 ($i:ident, $f:expr) => {
17 #[allow(non_upper_case_globals)]
18 pub const $i: f32x8 = f32x8::new([$f; 8]);
19 };
20}
21
22impl f32x8 {
23 const_f32_as_f32x8!(ONE, 1.0);
24 const_f32_as_f32x8!(HALF, 0.5);
25 const_f32_as_f32x8!(ZERO, 0.0);
26 const_f32_as_f32x8!(EPSILON, f32::EPSILON);
27 const_f32_as_f32x8!(MIN, f32::MIN);
28 const_f32_as_f32x8!(MIN_POSITIVE, f32::MIN_POSITIVE);
29 const_f32_as_f32x8!(MAX, f32::MAX);
30 const_f32_as_f32x8!(NAN, f32::NAN);
31 const_f32_as_f32x8!(INFINITY, f32::INFINITY);
32 const_f32_as_f32x8!(NEG_INFINITY, f32::NEG_INFINITY);
33 const_f32_as_f32x8!(E, core::f32::consts::E);
34 const_f32_as_f32x8!(FRAC_1_PI, core::f32::consts::FRAC_1_PI);
35 const_f32_as_f32x8!(FRAC_2_PI, core::f32::consts::FRAC_2_PI);
36 const_f32_as_f32x8!(FRAC_2_SQRT_PI, core::f32::consts::FRAC_2_SQRT_PI);
37 const_f32_as_f32x8!(FRAC_1_SQRT_2, core::f32::consts::FRAC_1_SQRT_2);
38 const_f32_as_f32x8!(FRAC_PI_2, core::f32::consts::FRAC_PI_2);
39 const_f32_as_f32x8!(FRAC_PI_3, core::f32::consts::FRAC_PI_3);
40 const_f32_as_f32x8!(FRAC_PI_4, core::f32::consts::FRAC_PI_4);
41 const_f32_as_f32x8!(FRAC_PI_6, core::f32::consts::FRAC_PI_6);
42 const_f32_as_f32x8!(FRAC_PI_8, core::f32::consts::FRAC_PI_8);
43 const_f32_as_f32x8!(LN_2, core::f32::consts::LN_2);
44 const_f32_as_f32x8!(LN_10, core::f32::consts::LN_10);
45 const_f32_as_f32x8!(LOG2_E, core::f32::consts::LOG2_E);
46 const_f32_as_f32x8!(LOG10_E, core::f32::consts::LOG10_E);
47 const_f32_as_f32x8!(LOG10_2, core::f32::consts::LOG10_2);
48 const_f32_as_f32x8!(LOG2_10, core::f32::consts::LOG2_10);
49 const_f32_as_f32x8!(PI, core::f32::consts::PI);
50 const_f32_as_f32x8!(SQRT_2, core::f32::consts::SQRT_2);
51 const_f32_as_f32x8!(TAU, core::f32::consts::TAU);
52}
53
54unsafe impl Zeroable for f32x8 {}
55unsafe impl Pod for f32x8 {}
56
57impl AlignTo for f32x8 {
58 type Elem = f32;
59}
60
61impl Add for f32x8 {
62 type Output = Self;
63 #[inline]
64 fn add(self, rhs: Self) -> Self::Output {
65 pick! {
66 if #[cfg(target_feature="avx")] {
67 Self { avx: add_m256(self.avx, rhs.avx) }
68 } else {
69 Self {
70 a : self.a.add(rhs.a),
71 b : self.b.add(rhs.b),
72 }
73 }
74 }
75 }
76}
77
78impl Sub for f32x8 {
79 type Output = Self;
80 #[inline]
81 fn sub(self, rhs: Self) -> Self::Output {
82 pick! {
83 if #[cfg(target_feature="avx")] {
84 Self { avx: sub_m256(self.avx, rhs.avx) }
85 } else {
86 Self {
87 a : self.a.sub(rhs.a),
88 b : self.b.sub(rhs.b),
89 }
90 }
91 }
92 }
93}
94
95impl Mul for f32x8 {
96 type Output = Self;
97 #[inline]
98 fn mul(self, rhs: Self) -> Self::Output {
99 pick! {
100 if #[cfg(target_feature="avx")] {
101 Self { avx: mul_m256(self.avx, rhs.avx) }
102 } else {
103 Self {
104 a : self.a.mul(rhs.a),
105 b : self.b.mul(rhs.b),
106 }
107 }
108 }
109 }
110}
111
112impl Div for f32x8 {
113 type Output = Self;
114 #[inline]
115 fn div(self, rhs: Self) -> Self::Output {
116 pick! {
117 if #[cfg(target_feature="avx")] {
118 Self { avx: div_m256(self.avx, rhs.avx) }
119 } else {
120 Self {
121 a : self.a.div(rhs.a),
122 b : self.b.div(rhs.b),
123 }
124 }
125 }
126 }
127}
128
129impl Rem for f32x8 {
130 type Output = Self;
131 #[inline]
132 fn rem(self, rhs: Self) -> Self::Output {
133 Self::new([
134 self.to_array()[0] % rhs.to_array()[0],
135 self.to_array()[1] % rhs.to_array()[1],
136 self.to_array()[2] % rhs.to_array()[2],
137 self.to_array()[3] % rhs.to_array()[3],
138 self.to_array()[4] % rhs.to_array()[4],
139 self.to_array()[5] % rhs.to_array()[5],
140 self.to_array()[6] % rhs.to_array()[6],
141 self.to_array()[7] % rhs.to_array()[7],
142 ])
143 }
144}
145
146impl Neg for f32x8 {
147 type Output = Self;
148 #[inline]
149 fn neg(self) -> Self::Output {
150 pick! {
151 if #[cfg(target_feature="avx")] {
152 Self { avx: bitxor_m256(self.avx, Self::splat(-0.0).avx) }
153 } else {
154 Self {
155 a : self.a.neg(),
156 b : self.b.neg(),
157 }
158 }
159 }
160 }
161}
162
163impl Add<f32> for f32x8 {
164 type Output = Self;
165 #[inline]
166 fn add(self, rhs: f32) -> Self::Output {
167 self.add(Self::splat(rhs))
168 }
169}
170
171impl Sub<f32> for f32x8 {
172 type Output = Self;
173 #[inline]
174 fn sub(self, rhs: f32) -> Self::Output {
175 self.sub(Self::splat(rhs))
176 }
177}
178
179impl Mul<f32> for f32x8 {
180 type Output = Self;
181 #[inline]
182 fn mul(self, rhs: f32) -> Self::Output {
183 self.mul(Self::splat(rhs))
184 }
185}
186
187impl Div<f32> for f32x8 {
188 type Output = Self;
189 #[inline]
190 fn div(self, rhs: f32) -> Self::Output {
191 self.div(Self::splat(rhs))
192 }
193}
194
195impl Rem<f32> for f32x8 {
196 type Output = Self;
197 #[inline]
198 fn rem(self, rhs: f32) -> Self::Output {
199 self.rem(Self::splat(rhs))
200 }
201}
202
203impl Add<f32x8> for f32 {
204 type Output = f32x8;
205 #[inline]
206 fn add(self, rhs: f32x8) -> Self::Output {
207 f32x8::splat(self).add(rhs)
208 }
209}
210
211impl Sub<f32x8> for f32 {
212 type Output = f32x8;
213 #[inline]
214 fn sub(self, rhs: f32x8) -> Self::Output {
215 f32x8::splat(self).sub(rhs)
216 }
217}
218
219impl Mul<f32x8> for f32 {
220 type Output = f32x8;
221 #[inline]
222 fn mul(self, rhs: f32x8) -> Self::Output {
223 f32x8::splat(self).mul(rhs)
224 }
225}
226
227impl Div<f32x8> for f32 {
228 type Output = f32x8;
229 #[inline]
230 fn div(self, rhs: f32x8) -> Self::Output {
231 f32x8::splat(self).div(rhs)
232 }
233}
234
235impl Rem<f32x8> for f32 {
236 type Output = f32x8;
237 #[inline]
238 fn rem(self, rhs: f32x8) -> Self::Output {
239 f32x8::splat(self).rem(rhs)
240 }
241}
242
243impl BitAnd for f32x8 {
244 type Output = Self;
245 #[inline]
246 fn bitand(self, rhs: Self) -> Self::Output {
247 pick! {
248 if #[cfg(target_feature="avx")] {
249 Self { avx: bitand_m256(self.avx, rhs.avx) }
250 } else {
251 Self {
252 a : self.a.bitand(rhs.a),
253 b : self.b.bitand(rhs.b),
254 }
255 }
256 }
257 }
258}
259
260impl BitOr for f32x8 {
261 type Output = Self;
262 #[inline]
263 fn bitor(self, rhs: Self) -> Self::Output {
264 pick! {
265 if #[cfg(target_feature="avx")] {
266 Self { avx: bitor_m256(self.avx, rhs.avx) }
267 } else {
268 Self {
269 a : self.a.bitor(rhs.a),
270 b : self.b.bitor(rhs.b),
271 }
272 }
273 }
274 }
275}
276
277impl BitXor for f32x8 {
278 type Output = Self;
279 #[inline]
280 fn bitxor(self, rhs: Self) -> Self::Output {
281 pick! {
282 if #[cfg(target_feature="avx")] {
283 Self { avx: bitxor_m256(self.avx, rhs.avx) }
284 } else {
285 Self {
286 a : self.a.bitxor(rhs.a),
287 b : self.b.bitxor(rhs.b),
288 }
289 }
290 }
291 }
292}
293
294#[expect(deprecated)]
295impl CmpEq for f32x8 {
296 type Output = Self;
297 #[inline]
298 fn simd_eq(self, rhs: Self) -> Self::Output {
299 pick! {
300 if #[cfg(target_feature="avx")] {
301 Self { avx: cmp_op_mask_m256::<{cmp_op!(EqualOrdered)}>(self.avx, rhs.avx) }
302 } else {
303 Self {
304 a : self.a.simd_eq(rhs.a),
305 b : self.b.simd_eq(rhs.b),
306 }
307 }
308 }
309 }
310}
311
312#[expect(deprecated)]
313impl CmpGe for f32x8 {
314 type Output = Self;
315 #[inline]
316 fn simd_ge(self, rhs: Self) -> Self::Output {
317 pick! {
318 if #[cfg(target_feature="avx")] {
319 Self { avx: cmp_op_mask_m256::<{cmp_op!(GreaterEqualOrdered)}>(self.avx, rhs.avx) }
320 } else {
321 Self {
322 a : self.a.simd_ge(rhs.a),
323 b : self.b.simd_ge(rhs.b),
324 }
325 }
326 }
327 }
328}
329
330#[expect(deprecated)]
331impl CmpGt for f32x8 {
332 type Output = Self;
333 #[inline]
334 fn simd_gt(self, rhs: Self) -> Self::Output {
335 pick! {
336 if #[cfg(target_feature="avx")] {
337 Self { avx: cmp_op_mask_m256::<{cmp_op!(GreaterThanOrdered)}>(self.avx, rhs.avx) }
338 } else {
339 Self {
340 a : self.a.simd_gt(rhs.a),
341 b : self.b.simd_gt(rhs.b),
342 }
343 }
344 }
345 }
346}
347
348#[expect(deprecated)]
349impl CmpNe for f32x8 {
350 type Output = Self;
351 #[inline]
352 fn simd_ne(self, rhs: Self) -> Self::Output {
353 pick! {
354 if #[cfg(target_feature="avx")] {
355 Self { avx: cmp_op_mask_m256::<{cmp_op!(NotEqualUnordered)}>(self.avx, rhs.avx) }
356 } else {
357 Self {
358 a : self.a.simd_ne(rhs.a),
359 b : self.b.simd_ne(rhs.b),
360 }
361 }
362 }
363 }
364}
365
366#[expect(deprecated)]
367impl CmpLe for f32x8 {
368 type Output = Self;
369 #[inline]
370 fn simd_le(self, rhs: Self) -> Self::Output {
371 pick! {
372 if #[cfg(target_feature="avx")] {
373 Self { avx: cmp_op_mask_m256::<{cmp_op!(LessEqualOrdered)}>(self.avx, rhs.avx) }
374 } else {
375 Self {
376 a : self.a.simd_le(rhs.a),
377 b : self.b.simd_le(rhs.b),
378 }
379 }
380 }
381 }
382}
383
384#[expect(deprecated)]
385impl CmpLt for f32x8 {
386 type Output = Self;
387 #[inline]
388 fn simd_lt(self, rhs: Self) -> Self::Output {
389 pick! {
390 if #[cfg(target_feature="avx")] {
391 Self { avx: cmp_op_mask_m256::<{cmp_op!(LessThanOrdered)}>(self.avx, rhs.avx) }
392 } else {
393 Self {
394 a : self.a.simd_lt(rhs.a),
395 b : self.b.simd_lt(rhs.b),
396 }
397 }
398 }
399 }
400}
401
402impl f32x8 {
403 #[inline]
404 #[must_use]
405 pub const fn new(array: [f32; 8]) -> Self {
406 unsafe { core::mem::transmute(array) }
407 }
408
409 simd_comparison_fns!();
410
411 #[inline]
412 #[must_use]
413 pub fn blend(self, t: Self, f: Self) -> Self {
414 pick! {
415 if #[cfg(target_feature="avx")] {
416 Self { avx: blend_varying_m256(f.avx, t.avx, self.avx) }
417 } else {
418 Self {
419 a : self.a.blend(t.a, f.a),
420 b : self.b.blend(t.b, f.b),
421 }
422 }
423 }
424 }
425 #[inline]
426 #[must_use]
427 pub fn abs(self) -> Self {
428 pick! {
429 if #[cfg(target_feature="avx")] {
430 let non_sign_bits = f32x8::from(f32::from_bits(i32::MAX as u32));
431 self & non_sign_bits
432 } else {
433 Self {
434 a : self.a.abs(),
435 b : self.b.abs(),
436 }
437 }
438 }
439 }
440
441 #[inline]
442 #[must_use]
443 pub fn signum(self) -> Self {
444 let result = Self::ONE | self & -Self::ZERO;
445
446 self.is_nan().blend(self, result)
447 }
448
449 #[inline]
450 #[must_use]
451 pub fn floor(self) -> Self {
452 pick! {
453 if #[cfg(target_feature="avx")] {
454 Self { avx: floor_m256(self.avx) }
455 } else {
456 Self {
457 a : self.a.floor(),
458 b : self.b.floor(),
459 }
460 }
461 }
462 }
463 #[inline]
464 #[must_use]
465 pub fn ceil(self) -> Self {
466 pick! {
467 if #[cfg(target_feature="avx")] {
468 Self { avx: ceil_m256(self.avx) }
469 } else {
470 Self {
471 a : self.a.ceil(),
472 b : self.b.ceil(),
473 }
474 }
475 }
476 }
477
478 #[inline]
482 #[must_use]
483 pub fn fast_max(self, rhs: Self) -> Self {
484 pick! {
485 if #[cfg(target_feature="avx")] {
486 Self { avx: max_m256(self.avx, rhs.avx) }
487 } else {
488 Self {
489 a : self.a.fast_max(rhs.a),
490 b : self.b.fast_max(rhs.b),
491 }
492 }
493 }
494 }
495
496 #[inline]
499 #[must_use]
500 pub fn max(self, rhs: Self) -> Self {
501 pick! {
502 if #[cfg(target_feature="avx")] {
503 rhs.is_nan().blend(self, Self { avx: max_m256(self.avx, rhs.avx) })
507 } else {
508 Self {
509 a : self.a.max(rhs.a),
510 b : self.b.max(rhs.b),
511 }
512 }
513
514 }
515 }
516
517 #[inline]
521 #[must_use]
522 pub fn fast_min(self, rhs: Self) -> Self {
523 pick! {
524 if #[cfg(target_feature="avx")] {
525 Self { avx: min_m256(self.avx, rhs.avx) }
526 } else {
527 Self {
528 a : self.a.fast_min(rhs.a),
529 b : self.b.fast_min(rhs.b),
530 }
531 }
532 }
533 }
534
535 #[inline]
539 #[must_use]
540 pub fn min(self, rhs: Self) -> Self {
541 pick! {
542 if #[cfg(target_feature="avx")] {
543 rhs.is_nan().blend(self, Self { avx: min_m256(self.avx, rhs.avx) })
547 } else {
548 Self {
549 a : self.a.min(rhs.a),
550 b : self.b.min(rhs.b),
551 }
552 }
553 }
554 }
555
556 #[inline]
561 #[must_use]
562 pub fn clamp(self, min: Self, max: Self) -> Self {
563 let is_nan = self.is_nan() | min.is_nan() | max.is_nan();
564 let clamped = self.fast_min(max).fast_max(min);
565 is_nan.blend(Self::splat(f32::NAN), clamped)
566 }
567
568 #[inline]
575 #[must_use]
576 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
577 pick! {
578 if #[cfg(target_feature="avx")] {
579 Self { avx: min_m256(max.avx, max_m256(min.avx, self.avx)) }
582 } else {
583 Self {
584 a: self.a.fast_clamp(min.a, max.a),
585 b: self.b.fast_clamp(min.b, max.b),
586 }
587 }
588 }
589 }
590
591 #[inline]
592 #[must_use]
593 pub fn midpoint(self, other: Self) -> Self {
594 (self + other) * 0.5
595 }
596
597 #[inline]
598 #[must_use]
599 pub fn is_nan(self) -> Self {
600 pick! {
601 if #[cfg(target_feature="avx")] {
602 Self { avx: cmp_op_mask_m256::<{cmp_op!(Unordered)}>(self.avx, self.avx) }
603 } else {
604 Self {
605 a : self.a.is_nan(),
606 b : self.b.is_nan(),
607 }
608 }
609 }
610 }
611 #[inline]
612 #[must_use]
613 pub fn is_finite(self) -> Self {
614 let shifted_exp_mask = u32x8::from(0xFF000000);
615 let u: u32x8 = cast(self);
616 let shift_u = u << 1_u64;
617 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
618 cast(out)
619 }
620 #[inline]
621 #[must_use]
622 pub fn is_inf(self) -> Self {
623 let shifted_inf = u32x8::from(0xFF000000);
624 let u: u32x8 = cast(self);
625 let shift_u = u << 1_u64;
626 let out = (shift_u).simd_eq(shifted_inf);
627 cast(out)
628 }
629
630 #[inline]
631 #[must_use]
632 pub fn round(self) -> Self {
633 pick! {
634 if #[cfg(target_feature="avx")] {
636 Self { avx: round_m256::<{round_op!(Nearest)}>(self.avx) }
637 } else {
638 Self {
639 a : self.a.round(),
640 b : self.b.round(),
641 }
642 }
643 }
644 }
645
646 #[inline]
650 #[must_use]
651 pub fn fast_round_int(self) -> i32x8 {
652 pick! {
653 if #[cfg(target_feature="avx")] {
654 cast(convert_to_i32_m256i_from_m256(self.avx))
655 } else {
656 cast([
657 self.a.fast_round_int(),
658 self.b.fast_round_int()])
659 }
660 }
661 }
662
663 #[inline]
667 #[must_use]
668 pub fn round_int(self) -> i32x8 {
669 pick! {
670 if #[cfg(target_feature="avx")] {
671 let non_nan_mask = self.simd_eq(self);
673 let non_nan = self & non_nan_mask;
674 let flip_to_max: i32x8 = cast(self.simd_ge(Self::splat(2147483648.0)));
675 let cast: i32x8 = cast(convert_to_i32_m256i_from_m256(non_nan.avx));
676 flip_to_max ^ cast
677 } else {
678 cast([
679 self.a.round_int(),
680 self.b.round_int(),
681 ])
682 }
683 }
684 }
685
686 #[inline]
687 #[must_use]
688 pub fn trunc(self) -> Self {
689 pick! {
690 if #[cfg(target_feature="avx")] {
691 Self { avx: round_m256::<{round_op!(Zero)}>(self.avx) }
692 } else {
693 Self {
694 a : self.a.trunc(),
695 b : self.b.trunc(),
696 }
697 }
698 }
699 }
700
701 #[inline]
705 #[must_use]
706 pub fn fast_trunc_int(self) -> i32x8 {
707 pick! {
708 if #[cfg(all(target_feature="avx"))] {
709 cast(convert_truncate_to_i32_m256i_from_m256(self.avx))
710 } else {
711 cast([
712 self.a.fast_trunc_int(),
713 self.b.fast_trunc_int(),
714 ])
715 }
716 }
717 }
718
719 #[inline]
723 #[must_use]
724 pub fn trunc_int(self) -> i32x8 {
725 pick! {
726 if #[cfg(target_feature="avx")] {
727 let non_nan_mask = self.simd_eq(self);
729 let non_nan = self & non_nan_mask;
730 let flip_to_max: i32x8 = cast(self.simd_ge(Self::splat(2147483648.0)));
731 let cast: i32x8 = cast(convert_truncate_to_i32_m256i_from_m256(non_nan.avx));
732 flip_to_max ^ cast
733 } else {
734 cast([
735 self.a.trunc_int(),
736 self.b.trunc_int(),
737 ])
738 }
739 }
740 }
741
742 #[inline]
743 #[must_use]
744 pub fn fract(self) -> Self {
745 self - self.trunc()
746 }
747
748 #[inline]
773 #[must_use]
774 pub fn mul_add(self, m: Self, a: Self) -> Self {
775 pick! {
776 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
777 Self { avx: fused_mul_add_m256(self.avx, m.avx, a.avx) }
778 } else if #[cfg(target_feature="avx")] {
779 (self * m) + a
781 } else {
782 Self {
783 a : self.a.mul_add(m.a, a.a),
784 b : self.b.mul_add(m.b, a.b),
785 }
786 }
787 }
788 }
789
790 #[inline]
815 #[must_use]
816 pub fn mul_sub(self, m: Self, s: Self) -> Self {
817 pick! {
818 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
819 Self { avx: fused_mul_sub_m256(self.avx, m.avx, s.avx) }
820 } else if #[cfg(target_feature="avx")] {
821 (self * m) - s
823 } else {
824 Self {
825 a : self.a.mul_sub(m.a, s.a),
826 b : self.b.mul_sub(m.b, s.b),
827 }
828 }
829 }
830 }
831
832 #[inline]
857 #[must_use]
858 pub fn mul_neg_add(self, m: Self, a: Self) -> Self {
859 pick! {
860 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
861 Self { avx: fused_mul_neg_add_m256(self.avx, m.avx, a.avx) }
862 } else if #[cfg(target_feature="avx")] {
863 a - (self * m)
865 } else {
866 Self {
867 a : self.a.mul_neg_add(m.a, a.a),
868 b : self.b.mul_neg_add(m.b, a.b),
869 }
870 }
871 }
872 }
873
874 #[inline]
899 #[must_use]
900 pub fn mul_neg_sub(self, m: Self, s: Self) -> Self {
901 pick! {
902 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
903 Self { avx: fused_mul_neg_sub_m256(self.avx, m.avx, s.avx) }
904 } else if #[cfg(target_feature="avx")] {
905 -(self * m) - s
907 } else {
908 Self {
909 a : self.a.mul_neg_sub(m.a, s.a),
910 b : self.b.mul_neg_sub(m.b, s.b),
911 }
912 }
913 }
914 }
915
916 #[inline]
917 #[must_use]
918 pub fn div_euclid(self, rhs: Self) -> Self {
919 let q = (self / rhs).trunc();
920 (self % rhs)
921 .simd_lt(Self::ZERO)
922 .blend(rhs.simd_gt(Self::ZERO).blend(q - Self::ONE, q + Self::ONE), q)
923 }
924
925 #[inline]
926 #[must_use]
927 pub fn rem_euclid(self, rhs: Self) -> Self {
928 let r = self % rhs;
929 r.simd_lt(Self::ZERO).blend(r + rhs.abs(), r)
930 }
931
932 #[inline]
933 #[must_use]
934 pub fn flip_signs(self, signs: Self) -> Self {
935 self ^ (signs & Self::from(-0.0))
936 }
937
938 #[inline]
939 #[must_use]
940 pub fn copysign(self, sign: Self) -> Self {
941 let magnitude_mask = Self::from(f32::from_bits(u32::MAX >> 1));
942 (self & magnitude_mask) | (sign & Self::from(-0.0))
943 }
944
945 #[inline]
946 pub fn asin_acos(self) -> (Self, Self) {
947 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
950 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
951 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
952 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
953 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
954
955 let xa = self.abs();
956 let big = xa.simd_ge(f32x8::splat(0.5));
957
958 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
959 let x2 = xa * xa;
960 let x3 = big.blend(x1, x2);
961
962 let xb = x1.sqrt();
963
964 let x4 = big.blend(xb, xa);
965
966 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
967 let z = z.mul_add(x3 * x4, x4);
968
969 let z1 = z + z;
970
971 let z3 = self.simd_lt(f32x8::ZERO).blend(f32x8::PI - z1, z1);
973 let z4 = f32x8::FRAC_PI_2 - z.flip_signs(self);
974 let acos = big.blend(z3, z4);
975
976 let z3 = f32x8::FRAC_PI_2 - z1;
978 let asin = big.blend(z3, z);
979 let asin = asin.flip_signs(self);
980
981 (asin, acos)
982 }
983
984 #[inline]
985 #[must_use]
986 pub fn asin(self) -> Self {
987 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
990 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
991 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
992 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
993 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
994
995 let xa = self.abs();
996 let big = xa.simd_ge(f32x8::splat(0.5));
997
998 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
999 let x2 = xa * xa;
1000 let x3 = big.blend(x1, x2);
1001
1002 let xb = x1.sqrt();
1003
1004 let x4 = big.blend(xb, xa);
1005
1006 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1007 let z = z.mul_add(x3 * x4, x4);
1008
1009 let z1 = z + z;
1010
1011 let z3 = f32x8::FRAC_PI_2 - z1;
1013 let asin = big.blend(z3, z);
1014 let asin = asin.flip_signs(self);
1015
1016 asin
1017 }
1018
1019 #[inline]
1020 #[must_use]
1021 pub fn acos(self) -> Self {
1022 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
1025 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
1026 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
1027 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
1028 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
1029
1030 let xa = self.abs();
1031 let big = xa.simd_ge(f32x8::splat(0.5));
1032
1033 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
1034 let x2 = xa * xa;
1035 let x3 = big.blend(x1, x2);
1036
1037 let xb = x1.sqrt();
1038
1039 let x4 = big.blend(xb, xa);
1040
1041 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1042 let z = z.mul_add(x3 * x4, x4);
1043
1044 let z1 = z + z;
1045
1046 let z3 = self.simd_lt(f32x8::ZERO).blend(f32x8::PI - z1, z1);
1048 let z4 = f32x8::FRAC_PI_2 - z.flip_signs(self);
1049 let acos = big.blend(z3, z4);
1050
1051 acos
1052 }
1053
1054 #[inline]
1055 pub fn atan(self) -> Self {
1056 const_f32_as_f32x8!(P3atanf, 8.05374449538E-2);
1059 const_f32_as_f32x8!(P2atanf, -1.38776856032E-1);
1060 const_f32_as_f32x8!(P1atanf, 1.99777106478E-1);
1061 const_f32_as_f32x8!(P0atanf, -3.33329491539E-1);
1062
1063 let t = self.abs();
1064
1065 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1069 let notbig = t.simd_le(Self::SQRT_2 + Self::ONE);
1070
1071 let mut s = notbig.blend(Self::FRAC_PI_4, Self::FRAC_PI_2);
1072 s = notsmal & s;
1073
1074 let mut a = notbig & t;
1075 a = notsmal.blend(a - Self::ONE, a);
1076 let mut b = notbig & Self::ONE;
1077 b = notsmal.blend(b + t, b);
1078 let z = a / b;
1079
1080 let zz = z * z;
1081
1082 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1084 re = re.mul_add(zz * z, z) + s;
1085
1086 re = (self.is_sign_negative()).blend(-re, re);
1088
1089 re
1090 }
1091
1092 #[inline]
1093 pub fn atan2(self, x: Self) -> Self {
1094 const_f32_as_f32x8!(P3atanf, 8.05374449538E-2);
1097 const_f32_as_f32x8!(P2atanf, -1.38776856032E-1);
1098 const_f32_as_f32x8!(P1atanf, 1.99777106478E-1);
1099 const_f32_as_f32x8!(P0atanf, -3.33329491539E-1);
1100
1101 let y = self;
1102
1103 let x1 = x.abs();
1105 let y1 = y.abs();
1106 let swapxy = y1.simd_gt(x1);
1107 let mut x2 = swapxy.blend(y1, x1);
1109 let mut y2 = swapxy.blend(x1, y1);
1110
1111 let both_infinite = x.is_inf() & y.is_inf();
1113 if both_infinite.any() {
1114 let minus_one = -Self::ONE;
1115 x2 = both_infinite.blend(x2 & minus_one, x2);
1116 y2 = both_infinite.blend(y2 & minus_one, y2);
1117 }
1118
1119 let t = y2 / x2;
1121
1122 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1125
1126 let a = notsmal.blend(t - Self::ONE, t);
1127 let b = notsmal.blend(t + Self::ONE, Self::ONE);
1128 let s = notsmal & Self::FRAC_PI_4;
1129 let z = a / b;
1130
1131 let zz = z * z;
1132
1133 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1135 re = re.mul_add(zz * z, z) + s;
1136
1137 re = swapxy.blend(Self::FRAC_PI_2 - re, re);
1139 re = ((x | y).simd_eq(Self::ZERO)).blend(Self::ZERO, re);
1140 re = (x.is_sign_negative()).blend(Self::PI - re, re);
1141
1142 re = (y.is_sign_negative()).blend(-re, re);
1144
1145 re
1146 }
1147
1148 #[inline]
1149 #[must_use]
1150 pub fn sin_cos(self) -> (Self, Self) {
1151 const_f32_as_f32x8!(DP1F, 0.78515625_f32 * 2.0);
1155 const_f32_as_f32x8!(DP2F, 2.4187564849853515625E-4_f32 * 2.0);
1156 const_f32_as_f32x8!(DP3F, 3.77489497744594108E-8_f32 * 2.0);
1157
1158 const_f32_as_f32x8!(P0sinf, -1.6666654611E-1);
1159 const_f32_as_f32x8!(P1sinf, 8.3321608736E-3);
1160 const_f32_as_f32x8!(P2sinf, -1.9515295891E-4);
1161
1162 const_f32_as_f32x8!(P0cosf, 4.166664568298827E-2);
1163 const_f32_as_f32x8!(P1cosf, -1.388731625493765E-3);
1164 const_f32_as_f32x8!(P2cosf, 2.443315711809948E-5);
1165
1166 const_f32_as_f32x8!(TWO_OVER_PI, 2.0 / core::f32::consts::PI);
1167
1168 let xa = self.abs();
1169
1170 let y = (xa * TWO_OVER_PI).round();
1172 let q: i32x8 = y.round_int();
1173
1174 let x = y.mul_neg_add(DP3F, y.mul_neg_add(DP2F, y.mul_neg_add(DP1F, xa)));
1175
1176 let x2 = x * x;
1177 let mut s = polynomial_2!(x2, P0sinf, P1sinf, P2sinf) * (x * x2) + x;
1178 let mut c = polynomial_2!(x2, P0cosf, P1cosf, P2cosf) * (x2 * x2)
1179 + f32x8::from(0.5).mul_neg_add(x2, f32x8::from(1.0));
1180
1181 let swap = !(q & i32x8::from(1)).simd_eq(i32x8::from(0));
1182
1183 let mut overflow: f32x8 = cast(q.simd_gt(i32x8::from(0x2000000)));
1184 overflow &= xa.is_finite();
1185 s = overflow.blend(f32x8::from(0.0), s);
1186 c = overflow.blend(f32x8::from(1.0), c);
1187
1188 let mut sin1 = cast::<_, f32x8>(swap).blend(c, s);
1190 let sign_sin: i32x8 = (q << 30) ^ cast::<_, i32x8>(self);
1191 sin1 = sin1.flip_signs(cast(sign_sin));
1192
1193 let mut cos1 = cast::<_, f32x8>(swap).blend(s, c);
1195 let sign_cos: i32x8 = ((q + i32x8::from(1)) & i32x8::from(2)) << 30;
1196 cos1 ^= cast::<_, f32x8>(sign_cos);
1197
1198 let finite = self.is_finite();
1200 let nan = Self::splat(f32::NAN);
1201 let sin_final = finite.blend(sin1, nan);
1202 let cos_final = finite.blend(cos1, nan);
1203
1204 (sin_final, cos_final)
1205 }
1206 #[inline]
1207 #[must_use]
1208 pub fn sin(self) -> Self {
1209 let (s, _) = self.sin_cos();
1210 s
1211 }
1212 #[inline]
1213 #[must_use]
1214 pub fn cos(self) -> Self {
1215 let (_, c) = self.sin_cos();
1216 c
1217 }
1218 #[inline]
1219 #[must_use]
1220 pub fn tan(self) -> Self {
1221 let (s, c) = self.sin_cos();
1222 s / c
1223 }
1224
1225 #[inline]
1227 #[must_use]
1228 pub fn sinh(self) -> Self {
1229 const_f32_as_f32x8!(P0, 1.0);
1230 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1231 const_f32_as_f32x8!(P2, 1.0 / 120.0);
1232 const_f32_as_f32x8!(P3, 1.0 / 5040.0);
1233 let a = self.abs();
1234 let small = a.simd_lt(f32x8::from(0.5));
1236 let t = a * a;
1237 let poly = a * polynomial_3!(t, P0, P1, P2, P3);
1238 let exp_based = {
1239 let e = a.exp();
1240 (e - Self::ONE / e) * Self::HALF
1241 };
1242 let result = small.blend(poly, exp_based);
1243 result.flip_signs(self)
1244 }
1245
1246 #[inline]
1248 #[must_use]
1249 pub fn cosh(self) -> Self {
1250 const_f32_as_f32x8!(P0, 1.0);
1251 const_f32_as_f32x8!(P1, 1.0 / 2.0);
1252 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1253 const_f32_as_f32x8!(P3, 1.0 / 720.0);
1254 let a = self.abs();
1255 let small = a.simd_lt(f32x8::from(0.5));
1257 let t = a * a;
1258 let poly = polynomial_3!(t, P0, P1, P2, P3);
1259 let exp_based = {
1260 let e = a.exp();
1261 (e + Self::ONE / e) * Self::HALF
1262 };
1263 small.blend(poly, exp_based)
1264 }
1265
1266 #[inline]
1268 #[must_use]
1269 pub fn tanh(self) -> Self {
1270 let a = self.abs();
1274 let large = a.simd_gt(f32x8::from(9.011));
1275 if large.all() {
1276 return Self::ONE.flip_signs(self);
1277 }
1278 let small = a.simd_lt(f32x8::from(2e-4));
1279 let exp_based = {
1280 let t = (Self::from(-2.0) * a).exp_m1();
1281 let pos = -t / (t + Self::from(2.0));
1282 pos.flip_signs(self)
1283 };
1284 let result = small.blend(self, exp_based);
1285 large.blend(Self::ONE.flip_signs(self), result)
1286 }
1287
1288 #[inline]
1290 #[must_use]
1291 pub fn cbrt(self) -> Self {
1292 let a = self.abs();
1293 let zero = a.simd_eq(Self::ZERO);
1294 if zero.all() {
1295 return self; }
1297 let inf = a.is_inf();
1298 let nan = self.is_nan();
1299
1300 let tiny = a.simd_lt(Self::from(f32::MIN_POSITIVE));
1301 let a_work = tiny.blend(a * Self::from(16777216.0), a);
1302
1303 let e = Self::exponent(a_work) + Self::ONE;
1304 let d = Self::fraction_2(a_work);
1305
1306 const_f32_as_f32x8!(C0, 2.2241257);
1313 const_f32_as_f32x8!(C1, -3.8095417);
1314 const_f32_as_f32x8!(C2, 5.8982625);
1315 const_f32_as_f32x8!(C3, -5.532182);
1316 const_f32_as_f32x8!(C4, 2.8208892);
1317 const_f32_as_f32x8!(C5, -0.60156447);
1318 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1319
1320 let x2 = x * x;
1321 let x4 = x2 * x2;
1322 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1323 let mut y = (d * x) * x;
1325 let yx = y * x;
1326 let t = Self::from(2.0 / 3.0);
1327 y = y - t * y * (yx - Self::ONE);
1328
1329 let three = Self::from(3.0);
1331 let two = Self::from(2.0);
1332 let neg = e.simd_lt(Self::ZERO);
1333 let e_adj = neg.blend(e - two, e);
1334 let k = (e_adj / three).trunc();
1335 let r = e - three * k;
1336 const_f32_as_f32x8!(CBRT2, 1.259921);
1337 const_f32_as_f32x8!(CBRT4, 1.587401);
1338 y = r.simd_eq(Self::ONE).blend(y * CBRT2, y);
1339 y = r.simd_eq(two).blend(y * CBRT4, y);
1340 y *= Self::vm_pow2n(k);
1341 y = tiny.blend(y / Self::from(256.0_f32), y);
1342
1343 let result = y.flip_signs(self);
1344 let result = nan.blend(self, result);
1345 let result = zero.blend(self, result);
1346 let result = inf.blend(self, result);
1347 result
1348 }
1349
1350 #[inline]
1351 #[must_use]
1352 pub fn to_degrees(self) -> Self {
1353 const_f32_as_f32x8!(RAD_TO_DEG_RATIO, 180.0_f32 / core::f32::consts::PI);
1354 self * RAD_TO_DEG_RATIO
1355 }
1356 #[inline]
1357 #[must_use]
1358 pub fn to_radians(self) -> Self {
1359 const_f32_as_f32x8!(DEG_TO_RAD_RATIO, core::f32::consts::PI / 180.0_f32);
1360 self * DEG_TO_RAD_RATIO
1361 }
1362 #[inline]
1363 #[must_use]
1364 pub fn recip(self) -> Self {
1365 pick! {
1366 if #[cfg(target_feature="avx")] {
1367 Self { avx: reciprocal_m256(self.avx) }
1368 } else {
1369 Self {
1370 a : self.a.recip(),
1371 b : self.b.recip(),
1372 }
1373 }
1374 }
1375 }
1376 #[inline]
1377 #[must_use]
1378 pub fn recip_sqrt(self) -> Self {
1379 pick! {
1380 if #[cfg(target_feature="avx")] {
1381 Self { avx: reciprocal_sqrt_m256(self.avx) }
1382 } else {
1383 Self {
1384 a : self.a.recip_sqrt(),
1385 b : self.b.recip_sqrt(),
1386 }
1387 }
1388 }
1389 }
1390 #[inline]
1391 #[must_use]
1392 pub fn sqrt(self) -> Self {
1393 pick! {
1394 if #[cfg(target_feature="avx")] {
1395 Self { avx: sqrt_m256(self.avx) }
1396 } else {
1397 Self {
1398 a : self.a.sqrt(),
1399 b : self.b.sqrt(),
1400 }
1401 }
1402 }
1403 }
1404 #[inline]
1405 #[must_use]
1406 #[doc(alias("movemask", "move_mask"))]
1407 pub fn to_bitmask(self) -> u32 {
1408 pick! {
1409 if #[cfg(target_feature="avx")] {
1410 move_mask_m256(self.avx) as u32
1411 } else {
1412 (self.b.to_bitmask() << 4) | self.a.to_bitmask()
1413 }
1414 }
1415 }
1416 #[inline]
1417 #[must_use]
1418 pub fn any(self) -> bool {
1419 pick! {
1420 if #[cfg(target_feature="avx")] {
1421 move_mask_m256(self.avx) != 0
1422 } else {
1423 self.a.any() || self.b.any()
1424 }
1425 }
1426 }
1427 #[inline]
1428 #[must_use]
1429 pub fn all(self) -> bool {
1430 pick! {
1431 if #[cfg(target_feature="avx")] {
1432 move_mask_m256(self.avx) == 0b11111111
1433 } else {
1434 self.a.all() && self.b.all()
1435 }
1436 }
1437 }
1438 #[inline]
1439 #[must_use]
1440 pub fn none(self) -> bool {
1441 !self.any()
1442 }
1443
1444 #[inline]
1445 fn vm_pow2n(self) -> Self {
1446 const_f32_as_f32x8!(pow2_23, 8388608.0);
1447 const_f32_as_f32x8!(bias, 127.0);
1448 let a = self + (bias + pow2_23);
1449 let c = cast::<_, i32x8>(a) << 23;
1450 let std_result = cast::<_, f32x8>(c);
1451
1452 let min_exp = f32x8::from(-126.0);
1453 let is_sub = self.simd_lt(min_exp);
1454 if is_sub.any() {
1455 let valid = self.simd_ge(f32x8::from(-149.0));
1456 let shift_f = self + f32x8::from(149.0);
1457 let mut shift_i = shift_f.trunc_int();
1458 shift_i = cast::<_, i32x8>(valid).blend(shift_i, i32x8::ZERO);
1459 let mantissa = i32x8::ONE << shift_i;
1460 let sub_result = cast::<_, f32x8>(mantissa);
1461 let sub_result = valid.blend(sub_result, f32x8::ZERO);
1462 is_sub.blend(sub_result, std_result)
1463 } else {
1464 std_result
1465 }
1466 }
1467
1468 #[inline]
1470 #[must_use]
1471 pub fn exp(self) -> Self {
1472 const_f32_as_f32x8!(P0, 1.0 / 2.0);
1473 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1474 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1475 const_f32_as_f32x8!(P3, 1.0 / 120.0);
1476 const_f32_as_f32x8!(P4, 1.0 / 720.0);
1477 const_f32_as_f32x8!(P5, 1.0 / 5040.0);
1478 const_f32_as_f32x8!(LN2D_HI, 0.693359375);
1485 const_f32_as_f32x8!(LN2D_LO, -2.12194440e-4);
1486 let max_x = f32x8::from(88.723);
1489 let min_x = f32x8::from(-103.63);
1490 let finite = self.is_finite();
1492 let neg_underflow = self.simd_lt(min_x) & finite;
1493 if neg_underflow.all() {
1494 return Self::ZERO;
1495 }
1496 let max_r = f32x8::from(127.0);
1497 let r = (self * Self::LOG2_E).round();
1498 let big = r.simd_gt(max_r);
1499 let r_safe = big.blend(max_r, r);
1500 let excess = r - max_r;
1501 let excess = big.blend(excess, Self::ZERO);
1502 let scale = Self::vm_pow2n(excess);
1503 let x = r.mul_neg_add(LN2D_HI, self);
1504 let x = r.mul_neg_add(LN2D_LO, x);
1505 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1506 let x2 = x * x;
1507 let z = z.mul_add(x2, x);
1508 let n2 = Self::vm_pow2n(r_safe);
1509 let z = (z + Self::ONE) * scale * n2;
1510 let nan_mask = self.is_nan();
1511 let mut result = nan_mask.blend(Self::nan_pow(), z);
1512 let pos_overflow = self.simd_gt(max_x) & finite;
1513 result = pos_overflow.blend(Self::infinity(), result);
1514 result = neg_underflow.blend(Self::ZERO, result);
1515 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1516 result = pos_inf.blend(Self::infinity(), result);
1517 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1518 result = neg_inf.blend(Self::ZERO, result);
1519 result
1520 }
1521
1522 #[inline]
1525 #[must_use]
1526 pub fn exp_m1(self) -> Self {
1527 if self.simd_lt(f32x8::from(-17.329)).all() {
1531 return f32x8::from(-1.0);
1532 }
1533 const_f32_as_f32x8!(P0, 1.0 / 2.0);
1534 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1535 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1536 const_f32_as_f32x8!(P3, 1.0 / 120.0);
1537 const_f32_as_f32x8!(P4, 1.0 / 720.0);
1538 const_f32_as_f32x8!(P5, 1.0 / 5040.0);
1539 const_f32_as_f32x8!(LN2D_HI, 0.693359375);
1546 const_f32_as_f32x8!(LN2D_LO, -2.12194440e-4);
1547 let max_x = f32x8::from(88.723);
1550 let min_x = f32x8::from(-103.63);
1551 let max_r = f32x8::from(127.0);
1552 let r = (self * Self::LOG2_E).round();
1553 let big = r.simd_gt(max_r);
1554 let r_safe = big.blend(max_r, r);
1555 let excess = r - max_r;
1556 let excess = big.blend(excess, Self::ZERO);
1557 let scale = Self::vm_pow2n(excess);
1558 let x = r.mul_neg_add(LN2D_HI, self);
1559 let x = r.mul_neg_add(LN2D_LO, x);
1560 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1561 let x2 = x * x;
1562 let z = z.mul_add(x2, x);
1563 let n2 = Self::vm_pow2n(r_safe);
1564 let exp_val = (z + Self::ONE) * scale * n2;
1565 let r_is_zero = r.simd_eq(Self::ZERO);
1566 let z = r_is_zero.blend(z, exp_val - Self::ONE);
1567 let nan_mask = self.is_nan();
1568 let finite = self.is_finite();
1569 let mut result = nan_mask.blend(Self::nan_pow(), z);
1570 let pos_overflow = self.simd_gt(max_x) & finite;
1571 result = pos_overflow.blend(Self::infinity(), result);
1572 let neg_underflow = self.simd_lt(min_x) & finite;
1573 result = neg_underflow.blend(-Self::ONE, result);
1574 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1575 result = pos_inf.blend(Self::infinity(), result);
1576 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1577 result = neg_inf.blend(-Self::ONE, result);
1578 let is_zero = self.simd_eq(Self::ZERO);
1579 result = is_zero.blend(self, result);
1580 result
1581 }
1582
1583 #[inline]
1585 #[must_use]
1586 pub fn exp2(self) -> Self {
1587 const_f32_as_f32x8!(P2, 1.0 / 2.0);
1588 const_f32_as_f32x8!(P3, 1.0 / 6.0);
1589 const_f32_as_f32x8!(P4, 1.0 / 24.0);
1590 const_f32_as_f32x8!(P5, 1.0 / 120.0);
1591 const_f32_as_f32x8!(P6, 1.0 / 720.0);
1592 const_f32_as_f32x8!(P7, 1.0 / 5040.0);
1593
1594 let max_x = f32x8::from(127.99999);
1597 let min_x = f32x8::from(-149.5);
1598 let finite = self.is_finite();
1599 let neg_underflow = self.simd_lt(min_x) & finite;
1600 if neg_underflow.all() {
1601 return Self::ZERO;
1602 }
1603
1604 let round = self.round();
1605 let max_r = f32x8::from(127.0);
1606 let big = round.simd_gt(max_r);
1607 let r_safe = big.blend(max_r, round);
1608 let excess = round - max_r;
1609 let excess = big.blend(excess, Self::ZERO);
1610 let scale = Self::vm_pow2n(excess);
1611
1612 let fract = (self - round) * Self::LN_2;
1613 let fract_partial_exp2 = polynomial_5!(fract, P2, P3, P4, P5, P6, P7);
1614 let fract2 = fract * fract;
1615 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1616
1617 let n2 = Self::vm_pow2n(r_safe);
1618 let result = fract_exp2 * scale * n2;
1619
1620 let nan_mask = self.is_nan();
1621 let mut result = nan_mask.blend(Self::nan_pow(), result);
1622 let pos_overflow = self.simd_gt(max_x) & finite;
1623 result = pos_overflow.blend(Self::infinity(), result);
1624 result = neg_underflow.blend(Self::ZERO, result);
1625 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1626 result = pos_inf.blend(Self::infinity(), result);
1627 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1628 result = neg_inf.blend(Self::ZERO, result);
1629 result
1630 }
1631
1632 #[inline]
1633 fn exponent(self) -> f32x8 {
1634 const_f32_as_f32x8!(pow2_23, 8388608.0);
1635 const_f32_as_f32x8!(bias, 127.0);
1636 let a = cast::<_, u32x8>(self);
1637 let b = a >> 23;
1638 let c = b | cast::<_, u32x8>(pow2_23);
1639 let d = cast::<_, f32x8>(c);
1640 let e = d - (pow2_23 + bias);
1641 e
1642 }
1643
1644 #[inline]
1645 fn fraction_2(self) -> Self {
1646 let t1 = cast::<_, u32x8>(self);
1647 let t2 = cast::<_, u32x8>(
1648 (t1 & u32x8::from(0x007FFFFF)) | u32x8::from(0x3F000000),
1649 );
1650 cast::<_, f32x8>(t2)
1651 }
1652 #[inline]
1653 fn is_zero_or_subnormal(self) -> Self {
1654 let t = cast::<_, i32x8>(self);
1655 let t = t & i32x8::splat(0x7F800000);
1656 let mask = t.simd_eq(i32x8::splat(0));
1657 cast::<_, f32x8>(mask)
1658 }
1659 #[inline]
1660 fn infinity() -> Self {
1661 cast::<_, f32x8>(i32x8::splat(0x7F800000))
1662 }
1663 #[inline]
1664 fn nan_log() -> Self {
1665 cast::<_, f32x8>(i32x8::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1666 }
1667 #[inline]
1668 fn nan_pow() -> Self {
1669 cast::<_, f32x8>(i32x8::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1670 }
1671
1672 #[inline]
1675 #[must_use]
1676 pub fn is_sign_positive(self) -> Self {
1677 const SIGN_MASK: u32x8 = u32x8::splat((-0.0_f32).to_bits());
1678
1679 let bits = cast::<f32x8, u32x8>(self);
1680 let sign = bits & SIGN_MASK;
1681 let result = sign.simd_eq(u32x8::ZERO);
1682 cast::<u32x8, f32x8>(result)
1683 }
1684
1685 #[inline]
1688 #[must_use]
1689 pub fn is_sign_negative(self) -> Self {
1690 const SIGN_MASK: u32x8 = u32x8::splat((-0.0_f32).to_bits());
1691
1692 let bits = cast::<f32x8, u32x8>(self);
1693 let sign = bits & SIGN_MASK;
1694 let result = sign.simd_eq(SIGN_MASK);
1695 cast::<u32x8, f32x8>(result)
1696 }
1697
1698 #[inline]
1700 #[must_use]
1701 pub fn reduce_add(self) -> f32 {
1702 pick! {
1703 if #[cfg(target_feature="avx")]{
1705 let hi_quad = extract_m128_from_m256::<1>(self.avx);
1706 let lo_quad = cast_to_m128_from_m256(self.avx);
1707 let sum_quad = add_m128(lo_quad,hi_quad);
1708 let lo_dual = sum_quad;
1709 let hi_dual = move_high_low_m128(sum_quad,sum_quad);
1710 let sum_dual = add_m128(lo_dual,hi_dual);
1711 let lo = sum_dual;
1712 let hi = shuffle_abi_f32_all_m128::<0b_01>(sum_dual, sum_dual);
1713 let sum = add_m128_s(lo, hi);
1714 get_f32_from_m128_s(sum)
1715 } else {
1716 self.a.reduce_add() + self.b.reduce_add()
1717 }
1718 }
1719 }
1720
1721 #[inline]
1723 #[must_use]
1724 pub fn reduce_mul(self) -> f32 {
1725 pick! {
1726 if #[cfg(target_feature="avx")] {
1728 let hi_quad = extract_m128_from_m256::<1>(self.avx);
1729 let lo_quad = cast_to_m128_from_m256(self.avx);
1730 let product_quad = mul_m128(lo_quad,hi_quad);
1731 let lo_dual = product_quad;
1732 let hi_dual = move_high_low_m128(product_quad, product_quad);
1733 let product_dual = mul_m128(lo_dual,hi_dual);
1734 let lo = product_dual;
1735 let hi = shuffle_abi_f32_all_m128::<0b_01>(product_dual, product_dual);
1736 let product = mul_m128_s(lo, hi);
1737 get_f32_from_m128_s(product)
1738 } else {
1739 self.a.reduce_mul() * self.b.reduce_mul()
1740 }
1741 }
1742 }
1743
1744 #[inline]
1746 #[must_use]
1747 pub fn ln(self) -> Self {
1748 const_f32_as_f32x8!(HALF, 0.5);
1749 const_f32_as_f32x8!(P0, 3.3333331174E-1);
1750 const_f32_as_f32x8!(P1, -2.4999993993E-1);
1751 const_f32_as_f32x8!(P2, 2.0000714765E-1);
1752 const_f32_as_f32x8!(P3, -1.6668057665E-1);
1753 const_f32_as_f32x8!(P4, 1.4249322787E-1);
1754 const_f32_as_f32x8!(P5, -1.2420140846E-1);
1755 const_f32_as_f32x8!(P6, 1.1676998740E-1);
1756 const_f32_as_f32x8!(P7, -1.1514610310E-1);
1757 const_f32_as_f32x8!(P8, 7.0376836292E-2);
1758 const_f32_as_f32x8!(LN2F_HI, 0.693359375);
1759 const_f32_as_f32x8!(LN2F_LO, -2.12194440e-4);
1760 const_f32_as_f32x8!(VM_SMALLEST_NORMAL, 1.17549435E-38);
1761
1762 let x1 = self;
1763 let x = Self::fraction_2(x1);
1764 let e = Self::exponent(x1);
1765 let mask = x.simd_gt(Self::SQRT_2 * HALF);
1766 let x = (!mask).blend(x + x, x);
1767 let fe = mask.blend(e + Self::ONE, e);
1768 let x = x - Self::ONE;
1769 let res = polynomial_8!(x, P0, P1, P2, P3, P4, P5, P6, P7, P8);
1770 let x2 = x * x;
1771 let res = x2 * x * res;
1772 let res = fe.mul_add(LN2F_LO, res);
1773 let res = res + x2.mul_neg_add(HALF, x);
1774 let res = fe.mul_add(LN2F_HI, res);
1775 let overflow = !self.is_finite();
1776 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1777 let mask = overflow | underflow;
1778 if !mask.any() {
1779 res
1780 } else {
1781 let is_zero = self.is_zero_or_subnormal();
1782 let res = underflow.blend(Self::nan_log(), res);
1783 let res = is_zero.blend(-Self::infinity(), res);
1788 let res = overflow.blend(self, res);
1789 let res = (!self.is_finite() & self.is_sign_negative())
1791 .blend(Self::nan_log(), res);
1792 res
1793 }
1794 }
1795
1796 #[inline]
1799 #[must_use]
1800 pub fn ln_1p(self) -> Self {
1801 let u = self + Self::ONE;
1809 let eq = u.simd_eq(Self::ONE);
1810 let ln_u = Self::ln(u);
1811 let correction = self * (ln_u / (u - Self::ONE));
1812 let result = eq.blend(self, correction);
1813 let over = u.is_inf();
1814 over.blend(ln_u, result)
1815 }
1816
1817 #[inline]
1818 #[must_use]
1819 pub fn log2(self) -> Self {
1820 Self::ln(self) * Self::LOG2_E
1821 }
1822 #[inline]
1823 #[must_use]
1824 pub fn log10(self) -> Self {
1825 Self::ln(self) * Self::LOG10_E
1826 }
1827
1828 #[inline]
1829 #[must_use]
1830 pub fn pow_f32x8(self, y: Self) -> Self {
1831 const_f32_as_f32x8!(ln2f_hi, 0.693359375);
1832 const_f32_as_f32x8!(ln2f_lo, -2.12194440e-4);
1833 const_f32_as_f32x8!(P0logf, 3.3333331174E-1);
1834 const_f32_as_f32x8!(P1logf, -2.4999993993E-1);
1835 const_f32_as_f32x8!(P2logf, 2.0000714765E-1);
1836 const_f32_as_f32x8!(P3logf, -1.6668057665E-1);
1837 const_f32_as_f32x8!(P4logf, 1.4249322787E-1);
1838 const_f32_as_f32x8!(P5logf, -1.2420140846E-1);
1839 const_f32_as_f32x8!(P6logf, 1.1676998740E-1);
1840 const_f32_as_f32x8!(P7logf, -1.1514610310E-1);
1841 const_f32_as_f32x8!(P8logf, 7.0376836292E-2);
1842
1843 const_f32_as_f32x8!(p2expf, 1.0 / 2.0); const_f32_as_f32x8!(p3expf, 1.0 / 6.0);
1845 const_f32_as_f32x8!(p4expf, 1.0 / 24.0);
1846 const_f32_as_f32x8!(p5expf, 1.0 / 120.0);
1847 const_f32_as_f32x8!(p6expf, 1.0 / 720.0);
1848 const_f32_as_f32x8!(p7expf, 1.0 / 5040.0);
1849
1850 let x1 = self.abs();
1851 let x = x1.fraction_2();
1852 let mask = x.simd_gt(f32x8::SQRT_2 * f32x8::HALF);
1853 let x = (!mask).blend(x + x, x);
1854
1855 let x = x - f32x8::ONE;
1856 let x2 = x * x;
1857 let lg1 = polynomial_8!(
1858 x, P0logf, P1logf, P2logf, P3logf, P4logf, P5logf, P6logf, P7logf, P8logf
1859 );
1860 let lg1 = lg1 * x2 * x;
1861
1862 let ef = x1.exponent();
1863 let ef = mask.blend(ef + f32x8::ONE, ef);
1864 let e1 = (ef * y).round();
1865 let yr = ef.mul_sub(y, e1);
1866
1867 let lg = f32x8::HALF.mul_neg_add(x2, x) + lg1;
1868 let x2_err = (f32x8::HALF * x).mul_sub(x, f32x8::HALF * x2);
1869 let lg_err = f32x8::HALF.mul_add(x2, lg - x) - lg1;
1870
1871 let e2 = (lg * y * f32x8::LOG2_E).round();
1872 let v = lg.mul_sub(y, e2 * ln2f_hi);
1873 let v = e2.mul_neg_add(ln2f_lo, v);
1874 let v = v - (lg_err + x2_err).mul_sub(y, yr * f32x8::LN_2);
1875
1876 let x = v;
1877 let e3 = (x * f32x8::LOG2_E).round();
1878 let x = e3.mul_neg_add(f32x8::LN_2, x);
1879 let x2 = x * x;
1880 let z = x2.mul_add(
1881 polynomial_5!(x, p2expf, p3expf, p4expf, p5expf, p6expf, p7expf),
1882 x + f32x8::ONE,
1883 );
1884
1885 let ee = e1 + e2 + e3;
1886 let ei = cast::<_, i32x8>(ee.round_int());
1887 let ej = cast::<_, i32x8>(ei + (cast::<_, i32x8>(z) >> 23));
1888
1889 let overflow = cast::<_, f32x8>(ej.simd_gt(i32x8::splat(0x0FF)))
1890 | (ee.simd_gt(f32x8::splat(300.0)));
1891 let underflow = cast::<_, f32x8>(ej.simd_lt(i32x8::splat(0x000)))
1892 | (ee.simd_lt(f32x8::splat(-300.0)));
1893
1894 let z = cast::<_, f32x8>(cast::<_, i32x8>(z) + (ei << 23));
1896 let z = underflow.blend(f32x8::ZERO, z);
1898 let z = overflow.blend(Self::infinity(), z);
1899
1900 let x_zero = self.is_zero_or_subnormal();
1902 let z = x_zero.blend(
1903 y.simd_lt(f32x8::ZERO).blend(
1904 Self::infinity(),
1905 y.simd_eq(f32x8::ZERO).blend(f32x8::ONE, f32x8::ZERO),
1906 ),
1907 z,
1908 );
1909
1910 let x_sign = self.is_sign_negative();
1911 let z = if x_sign.any() {
1912 let yi = y.simd_eq(y.round());
1914
1915 let y_odd = cast::<_, i32x8>(y.round_int() << 31).round_float();
1917
1918 let z1 =
1919 yi.blend(z | y_odd, self.simd_eq(Self::ZERO).blend(z, Self::nan_pow()));
1920
1921 x_sign.blend(z1, z)
1922 } else {
1923 z
1924 };
1925
1926 let x_finite = self.is_finite();
1927 let y_finite = y.is_finite();
1928 let e_finite = ee.is_finite();
1929 if (x_finite & y_finite & (e_finite | x_zero)).all() {
1930 return z;
1931 }
1932
1933 (self.is_nan() | y.is_nan()).blend(self + y, z)
1934 }
1935 #[inline]
1936 pub fn powf(self, y: f32) -> Self {
1937 Self::pow_f32x8(self, f32x8::splat(y))
1938 }
1939
1940 #[must_use]
1942 #[inline]
1943 pub fn transpose(data: [f32x8; 8]) -> [f32x8; 8] {
1944 pick! {
1945 if #[cfg(target_feature="avx")] {
1946 let a0 = unpack_lo_m256(data[0].avx, data[1].avx);
1947 let a1 = unpack_hi_m256(data[0].avx, data[1].avx);
1948 let a2 = unpack_lo_m256(data[2].avx, data[3].avx);
1949 let a3 = unpack_hi_m256(data[2].avx, data[3].avx);
1950 let a4 = unpack_lo_m256(data[4].avx, data[5].avx);
1951 let a5 = unpack_hi_m256(data[4].avx, data[5].avx);
1952 let a6 = unpack_lo_m256(data[6].avx, data[7].avx);
1953 let a7 = unpack_hi_m256(data[6].avx, data[7].avx);
1954
1955 pub const fn mm_shuffle(z: i32, y: i32, x: i32, w: i32) -> i32 {
1956 (z << 6) | (y << 4) | (x << 2) | w
1957 }
1958
1959 const SHUFF_LO : i32 = mm_shuffle(1,0,1,0);
1960 const SHUFF_HI : i32 = mm_shuffle(3,2,3,2);
1961
1962 let b0 = shuffle_m256::<SHUFF_LO>(a0,a2);
1965 let b1 = shuffle_m256::<SHUFF_HI>(a0,a2);
1966 let b2 = shuffle_m256::<SHUFF_LO>(a1,a3);
1967 let b3 = shuffle_m256::<SHUFF_HI>(a1,a3);
1968 let b4 = shuffle_m256::<SHUFF_LO>(a4,a6);
1969 let b5 = shuffle_m256::<SHUFF_HI>(a4,a6);
1970 let b6 = shuffle_m256::<SHUFF_LO>(a5,a7);
1971 let b7 = shuffle_m256::<SHUFF_HI>(a5,a7);
1972
1973 [
1974 f32x8 { avx: permute2z_m256::<0x20>(b0, b4) },
1975 f32x8 { avx: permute2z_m256::<0x20>(b1, b5) },
1976 f32x8 { avx: permute2z_m256::<0x20>(b2, b6) },
1977 f32x8 { avx: permute2z_m256::<0x20>(b3, b7) },
1978 f32x8 { avx: permute2z_m256::<0x31>(b0, b4) },
1979 f32x8 { avx: permute2z_m256::<0x31>(b1, b5) },
1980 f32x8 { avx: permute2z_m256::<0x31>(b2, b6) },
1981 f32x8 { avx: permute2z_m256::<0x31>(b3, b7) }
1982 ]
1983 } else {
1984 #[inline(always)]
1987 fn transpose_column(data: &[f32x8; 8], index: usize) -> f32x8 {
1988 f32x8::new([
1989 data[0].as_array()[index],
1990 data[1].as_array()[index],
1991 data[2].as_array()[index],
1992 data[3].as_array()[index],
1993 data[4].as_array()[index],
1994 data[5].as_array()[index],
1995 data[6].as_array()[index],
1996 data[7].as_array()[index],
1997 ])
1998 }
1999
2000 [
2001 transpose_column(&data, 0),
2002 transpose_column(&data, 1),
2003 transpose_column(&data, 2),
2004 transpose_column(&data, 3),
2005 transpose_column(&data, 4),
2006 transpose_column(&data, 5),
2007 transpose_column(&data, 6),
2008 transpose_column(&data, 7),
2009 ]
2010 }
2011 }
2012 }
2013
2014 #[inline]
2015 pub fn to_array(self) -> [f32; 8] {
2016 cast(self)
2017 }
2018
2019 #[inline]
2020 pub fn as_array(&self) -> &[f32; 8] {
2021 cast_ref(self)
2022 }
2023
2024 #[inline]
2025 pub fn as_mut_array(&mut self) -> &mut [f32; 8] {
2026 cast_mut(self)
2027 }
2028
2029 #[inline]
2030 pub fn from_i32x8(v: i32x8) -> Self {
2031 pick! {
2032 if #[cfg(target_feature="avx2")] {
2033 Self { avx: convert_to_m256_from_i32_m256i(v.avx2) }
2034 } else {
2035 Self::new([
2036 v.as_array()[0] as f32,
2037 v.as_array()[1] as f32,
2038 v.as_array()[2] as f32,
2039 v.as_array()[3] as f32,
2040 v.as_array()[4] as f32,
2041 v.as_array()[5] as f32,
2042 v.as_array()[6] as f32,
2043 v.as_array()[7] as f32,
2044 ])
2045 }
2046 }
2047 }
2048
2049 #[inline]
2056 #[must_use]
2057 #[deprecated(since = "1.4.0", note = "renamed to `is_sign_negative`")]
2058 pub fn sign_bit(self) -> Self {
2059 self.is_sign_negative()
2060 }
2061}
2062
2063impl Not for f32x8 {
2064 type Output = Self;
2065 #[inline]
2066 fn not(self) -> Self {
2067 pick! {
2068 if #[cfg(target_feature="avx")] {
2069 Self { avx: self.avx.not() }
2070 } else {
2071 Self {
2072 a : self.a.not(),
2073 b : self.b.not(),
2074 }
2075 }
2076 }
2077 }
2078}