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