1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx512f")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
12 #[repr(C, align(64))]
13 pub struct f32x16 { pub(crate) avx512: m512 }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq)]
22 #[repr(C, align(64))]
23 pub struct f32x16 { pub(crate) a : f32x8, pub(crate) b : f32x8 }
24 }
25}
26
27macro_rules! const_f32_as_f32x16 {
28 ($i:ident, $f:expr) => {
29 #[allow(non_upper_case_globals)]
30 pub const $i: f32x16 = f32x16::new([$f; 16]);
31 };
32}
33
34impl_simd_float! {
35 unsafe {
36 T = f32,
37 N = 16,
38 Simd = f32x16,
39 IntSimd = i32x16,
40 UintT = u32,
41 UintSimd = u32x16,
42 optional_type_x86_inner { X86Inner = __m512 },
43 optional_type_arm_inner {},
44 optional_type_wasm_inner {},
45 }
46 old_powf_simd_fn_name = pow_f32x16,
47
48 #[inline]
49 fn neg(self) -> Self::Output {
50 pick! {
51 if #[cfg(target_feature="avx512f")] {
52 Self { avx512: bitxor_m512(self.avx512, Self::splat(-0.0).avx512) }
53 } else {
54 Self {
55 a : self.a.neg(),
56 b : self.b.neg(),
57 }
58 }
59 }
60 }
61
62 #[inline]
63 fn not(self) -> Self::Output {
64 pick! {
65 if #[cfg(target_feature="avx512f")] {
66 Self { avx512: bitxor_m512(self.avx512, set_splat_m512(f32::from_bits(u32::MAX))) }
67 } else {
68 Self {
69 a : self.a.not(),
70 b : self.b.not(),
71 }
72 }
73 }
74 }
75
76 #[inline]
77 fn add(self, rhs: Self) -> Self::Output {
78 pick! {
79 if #[cfg(target_feature="avx512f")] {
80 Self { avx512: add_m512(self.avx512, rhs.avx512) }
81 } else {
82 Self {
83 a : self.a.add(rhs.a),
84 b : self.b.add(rhs.b),
85 }
86 }
87 }
88 }
89
90 #[inline]
91 fn sub(self, rhs: Self) -> Self::Output {
92 pick! {
93 if #[cfg(target_feature="avx512f")] {
94 Self { avx512: sub_m512(self.avx512, rhs.avx512) }
95 } else {
96 Self {
97 a : self.a.sub(rhs.a),
98 b : self.b.sub(rhs.b),
99 }
100 }
101 }
102 }
103
104 #[inline]
105 fn mul(self, rhs: Self) -> Self::Output {
106 pick! {
107 if #[cfg(target_feature="avx512f")] {
108 Self { avx512: mul_m512(self.avx512, rhs.avx512) }
109 } else {
110 Self { a: self.a.mul(rhs.a), b: self.b.mul(rhs.b) }
111 }
112 }
113 }
114
115 #[inline]
116 fn div(self, rhs: Self) -> Self::Output {
117 pick! {
118 if #[cfg(target_feature="avx512f")] {
119 Self { avx512: div_m512(self.avx512, rhs.avx512) }
120 } else {
121 Self { a: self.a.div(rhs.a), b: self.b.div(rhs.b) }
122 }
123 }
124 }
125
126 #[inline]
127 fn rem(self, rhs: Self) -> Self::Output {
128 Self::new([
129 self.to_array()[0] % rhs.to_array()[0],
130 self.to_array()[1] % rhs.to_array()[1],
131 self.to_array()[2] % rhs.to_array()[2],
132 self.to_array()[3] % rhs.to_array()[3],
133 self.to_array()[4] % rhs.to_array()[4],
134 self.to_array()[5] % rhs.to_array()[5],
135 self.to_array()[6] % rhs.to_array()[6],
136 self.to_array()[7] % rhs.to_array()[7],
137 self.to_array()[8] % rhs.to_array()[8],
138 self.to_array()[9] % rhs.to_array()[9],
139 self.to_array()[10] % rhs.to_array()[10],
140 self.to_array()[11] % rhs.to_array()[11],
141 self.to_array()[12] % rhs.to_array()[12],
142 self.to_array()[13] % rhs.to_array()[13],
143 self.to_array()[14] % rhs.to_array()[14],
144 self.to_array()[15] % rhs.to_array()[15],
145 ])
146 }
147
148 #[inline]
149 fn bitand(self, rhs: Self) -> Self::Output {
150 pick! {
151 if #[cfg(target_feature="avx512f")] {
152 Self { avx512: bitand_m512(self.avx512, rhs.avx512) }
153 } else {
154 Self {
155 a : self.a.bitand(rhs.a),
156 b : self.b.bitand(rhs.b),
157 }
158 }
159 }
160 }
161
162 #[inline]
163 fn bitor(self, rhs: Self) -> Self::Output {
164 pick! {
165 if #[cfg(target_feature="avx512f")] {
166 Self { avx512: bitor_m512(self.avx512, rhs.avx512) }
167 } else {
168 Self {
169 a : self.a.bitor(rhs.a),
170 b : self.b.bitor(rhs.b),
171 }
172 }
173 }
174 }
175
176 #[inline]
177 fn bitxor(self, rhs: Self) -> Self::Output {
178 pick! {
179 if #[cfg(target_feature="avx512f")] {
180 Self { avx512: bitxor_m512(self.avx512, rhs.avx512) }
181 } else {
182 Self {
183 a : self.a.bitxor(rhs.a),
184 b : self.b.bitxor(rhs.b),
185 }
186 }
187 }
188 }
189
190 #[inline]
191 fn simd_eq(self, rhs: Self) -> Self::Output {
192 pick! {
193 if #[cfg(target_feature="avx512f")] {
194 Self { avx512: cmp_op_mask_m512::<{cmp_op!(EqualOrdered)}>(self.avx512, rhs.avx512) }
195 } else {
196 Self {
197 a : self.a.simd_eq(rhs.a),
198 b : self.b.simd_eq(rhs.b),
199 }
200 }
201 }
202 }
203
204 #[inline]
205 fn simd_ne(self, rhs: Self) -> Self::Output {
206 pick! {
207 if #[cfg(target_feature="avx512f")] {
208 Self { avx512: cmp_op_mask_m512::<{cmp_op!(NotEqualUnordered)}>(self.avx512, rhs.avx512) }
209 } else {
210 Self {
211 a : self.a.simd_ne(rhs.a),
212 b : self.b.simd_ne(rhs.b),
213 }
214 }
215 }
216 }
217
218 #[inline]
219 fn simd_lt(self, rhs: Self) -> Self::Output {
220 pick! {
221 if #[cfg(target_feature="avx512f")] {
222 Self { avx512: cmp_op_mask_m512::<{cmp_op!(LessThanOrdered)}>(self.avx512, rhs.avx512) }
223 } else {
224 Self {
225 a : self.a.simd_lt(rhs.a),
226 b : self.b.simd_lt(rhs.b),
227 }
228 }
229 }
230 }
231
232 #[inline]
233 fn simd_gt(self, rhs: Self) -> Self::Output {
234 pick! {
235 if #[cfg(target_feature="avx512f")] {
236 Self { avx512: cmp_op_mask_m512::<{cmp_op!(GreaterThanOrdered)}>(self.avx512, rhs.avx512) }
237 } else {
238 Self {
239 a : self.a.simd_gt(rhs.a),
240 b : self.b.simd_gt(rhs.b),
241 }
242 }
243 }
244 }
245
246 #[inline]
247 fn simd_le(self, rhs: Self) -> Self::Output {
248 pick! {
249 if #[cfg(target_feature="avx512f")] {
250 Self { avx512: cmp_op_mask_m512::<{cmp_op!(LessEqualOrdered)}>(self.avx512, rhs.avx512) }
251 } else {
252 Self {
253 a : self.a.simd_le(rhs.a),
254 b : self.b.simd_le(rhs.b),
255 }
256 }
257 }
258 }
259
260 #[inline]
261 fn simd_ge(self, rhs: Self) -> Self::Output {
262 pick! {
263 if #[cfg(target_feature="avx512f")] {
264 Self { avx512: cmp_op_mask_m512::<{cmp_op!(GreaterEqualOrdered)}>(self.avx512, rhs.avx512) }
265 } else {
266 Self {
267 a : self.a.simd_ge(rhs.a),
268 b : self.b.simd_ge(rhs.b),
269 }
270 }
271 }
272 }
273
274 #[inline]
275 pub fn reduce_add(self) -> f32 {
276 pick! {
277 if #[cfg(target_feature="avx512f")]{
278 reduce_add_m512(self.avx512)
279 } else {
280 self.a.reduce_add() + self.b.reduce_add()
281 }
282 }
283 }
284
285 #[inline]
286 pub fn reduce_mul(self) -> f32 {
287 pick! {
288 if #[cfg(target_feature="avx512f")] {
289 #[cfg(target_arch = "x86")]
292 use core::arch::x86::_mm512_reduce_mul_ps;
293 #[cfg(target_arch = "x86_64")]
294 use core::arch::x86_64::_mm512_reduce_mul_ps;
295
296 unsafe { _mm512_reduce_mul_ps(self.avx512.0) }
297 } else {
298 self.a.reduce_mul() * self.b.reduce_mul()
299 }
300 }
301 }
302
303 #[inline]
304 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
305 pick! {
306 if #[cfg(target_feature="avx512f")] {
307 Self {
308 avx512: bitor_m512(
309 bitand_m512(if_one.avx512, self.avx512),
310 bitandnot_m512(self.avx512, if_zero.avx512),
311 ),
312 }
313 } else {
314 Self {
315 a: self.a.bitselect(if_one.a, if_zero.a),
316 b: self.b.bitselect(if_one.b, if_zero.b),
317 }
318 }
319 }
320 }
321
322 #[inline]
323 fn select(self, if_true: Self, if_false: Self) -> Self {
324 pick! {
325 if #[cfg(target_feature="avx512f")] {
326 Self { avx512: blend_varying_m512(if_false.avx512, if_true.avx512, movepi32_mask_m512(self.avx512)) }
327 } else {
328 Self {
329 a : self.a.select(if_true.a, if_false.a),
330 b : self.b.select(if_true.b, if_false.b),
331 }
332 }
333 }
334 }
335
336 #[inline]
337 pub fn to_bitmask(self) -> u32 {
338 pick! {
339 if #[cfg(target_feature="avx512f")] {
340 movepi32_mask_m512(self.avx512) as u32
341 } else {
342 (self.b.to_bitmask() << 8) | self.a.to_bitmask()
343 }
344 }
345 }
346
347 #[inline]
348 pub fn any(self) -> bool {
349 pick! {
350 if #[cfg(target_feature="avx512f")] {
351 movepi32_mask_m512(self.avx512) != 0
352 } else {
353 self.a.any() || self.b.any()
354 }
355 }
356 }
357
358 #[inline]
359 pub fn all(self) -> bool {
360 pick! {
361 if #[cfg(target_feature="avx512f")] {
362 movepi32_mask_m512(self.avx512) == !0_u16
363 } else {
364 self.a.all() && self.b.all()
365 }
366 }
367 }
368
369 #[inline]
372 pub fn transpose(data: [f32x16; 16]) -> [f32x16; 16] {
373 #[inline(always)]
377 fn transpose_column(data: &[f32x16; 16], index: usize) -> f32x16 {
378 f32x16::new([
379 data[0].as_array()[index],
380 data[1].as_array()[index],
381 data[2].as_array()[index],
382 data[3].as_array()[index],
383 data[4].as_array()[index],
384 data[5].as_array()[index],
385 data[6].as_array()[index],
386 data[7].as_array()[index],
387 data[8].as_array()[index],
388 data[9].as_array()[index],
389 data[10].as_array()[index],
390 data[11].as_array()[index],
391 data[12].as_array()[index],
392 data[13].as_array()[index],
393 data[14].as_array()[index],
394 data[15].as_array()[index],
395 ])
396 }
397
398 [
399 transpose_column(&data, 0),
400 transpose_column(&data, 1),
401 transpose_column(&data, 2),
402 transpose_column(&data, 3),
403 transpose_column(&data, 4),
404 transpose_column(&data, 5),
405 transpose_column(&data, 6),
406 transpose_column(&data, 7),
407 transpose_column(&data, 8),
408 transpose_column(&data, 9),
409 transpose_column(&data, 10),
410 transpose_column(&data, 11),
411 transpose_column(&data, 12),
412 transpose_column(&data, 13),
413 transpose_column(&data, 14),
414 transpose_column(&data, 15),
415 ]
416 }
417
418 #[inline]
419 pub fn is_nan(self) -> Self {
420 pick! {
421 if #[cfg(target_feature = "avx512f")] {
422 Self { avx512: cmp_op_mask_m512::<{cmp_op!(Unordered)}>(self.avx512, self.avx512) }
423 } else {
424 Self {
425 a: self.a.is_nan(),
426 b: self.b.is_nan(),
427 }
428 }
429 }
430 }
431
432 #[inline]
433 pub fn is_inf(self) -> Self {
434 let shifted_inf = u32x16::from(0xFF000000);
435 let u: u32x16 = cast(self);
436 let shift_u = u << 1_u64;
437 let out = (shift_u).simd_eq(shifted_inf);
438 cast(out)
439 }
440
441 #[inline]
442 pub fn is_finite(self) -> Self {
443 let shifted_exp_mask = u32x16::splat(0xFF000000);
444 let u: u32x16 = cast(self);
445 let shift_u = u << 1_u32;
446 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
447 cast(out)
448 }
449
450 #[inline]
451 pub fn is_sign_positive(self) -> Self {
452 const SIGN_MASK: u32x16 = u32x16::splat((-0.0_f32).to_bits());
453
454 let bits = cast::<f32x16, u32x16>(self);
455 let sign = bits & SIGN_MASK;
456 let result = sign.simd_eq(u32x16::ZERO);
457 cast::<u32x16, f32x16>(result)
458 }
459
460 #[inline]
461 pub fn is_sign_negative(self) -> Self {
462 const SIGN_MASK: u32x16 = u32x16::splat((-0.0_f32).to_bits());
463
464 let bits = cast::<f32x16, u32x16>(self);
465 let sign = bits & SIGN_MASK;
466 let result = sign.simd_eq(SIGN_MASK);
467 cast::<u32x16, f32x16>(result)
468 }
469
470 #[inline]
471 pub fn recip(self) -> Self {
472 pick! {
473 if #[cfg(target_feature="avx512f")] {
474 1.0 / self
478 } else {
479 Self {
480 a : self.a.recip(),
481 b : self.b.recip(),
482 }
483 }
484 }
485 }
486
487 #[inline]
488 pub fn recip_sqrt(self) -> Self {
489 pick! {
490 if #[cfg(target_feature="avx512f")] {
491 self.sqrt().recip()
495 } else {
496 Self {
497 a : self.a.recip_sqrt(),
498 b : self.b.recip_sqrt(),
499 }
500 }
501 }
502 }
503
504 #[inline]
505 pub fn max(self, rhs: Self) -> Self {
506 pick! {
507 if #[cfg(target_feature="avx512f")] {
508 rhs.is_nan().select(self, Self { avx512: max_m512(self.avx512, rhs.avx512) })
512 } else {
513 Self {
514 a: self.a.max(rhs.a),
515 b: self.b.max(rhs.b),
516 }
517 }
518 }
519 }
520
521 #[inline]
522 pub fn fast_max(self, rhs: Self) -> Self {
523 pick! {
524 if #[cfg(target_feature="avx512f")] {
525 Self { avx512: max_m512(self.avx512, rhs.avx512) }
526 } else {
527 Self {
528 a: self.a.fast_max(rhs.a),
529 b: self.b.fast_max(rhs.b),
530 }
531 }
532 }
533 }
534
535 #[inline]
536 pub fn min(self, rhs: Self) -> Self {
537 pick! {
538 if #[cfg(target_feature="avx512f")] {
539 rhs.is_nan().select(self, Self { avx512: min_m512(self.avx512, rhs.avx512) })
543 } else {
544 Self {
545 a: self.a.min(rhs.a),
546 b: self.b.min(rhs.b),
547 }
548 }
549 }
550 }
551
552 #[inline]
553 pub fn fast_min(self, rhs: Self) -> Self {
554 pick! {
555 if #[cfg(target_feature="avx512f")] {
556 Self { avx512: min_m512(self.avx512, rhs.avx512) }
557 } else {
558 Self {
559 a: self.a.fast_min(rhs.a),
560 b: self.b.fast_min(rhs.b),
561 }
562 }
563 }
564 }
565
566 #[inline]
567 pub fn clamp(self, min: Self, max: Self) -> Self {
568 pick! {
569 if #[cfg(target_feature="avx512f")] {
570 self.fast_clamp(min, max) | min.is_nan() | max.is_nan()
572 } else {
573 Self {
575 a: self.a.clamp(min.a, max.a),
576 b: self.b.clamp(min.b, max.b),
577 }
578 }
579 }
580 }
581
582 #[inline]
583 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
584 pick! {
585 if #[cfg(target_feature="avx512f")] {
586 Self { avx512: max_m512(min.avx512, min_m512(max.avx512, self.avx512)) }
589 } else {
590 Self {
591 a: self.a.fast_clamp(min.a, max.a),
592 b: self.b.fast_clamp(min.b, max.b),
593 }
594 }
595 }
596 }
597
598 #[inline]
599 pub fn abs(self) -> Self {
600 pick! {
601 if #[cfg(target_feature="avx512f")] {
602 let non_sign_bits = f32x16::from(f32::from_bits(i32::MAX as u32));
603 self & non_sign_bits
604 } else {
605 Self {
606 a : self.a.abs(),
607 b : self.b.abs(),
608 }
609 }
610 }
611 }
612
613 #[inline]
614 pub fn floor(self) -> Self {
615 pick! {
616 if #[cfg(target_feature="avx512f")] {
617 Self { avx512: round_m512::<{round_op!(NegInf)}>(self.avx512) }
618 } else {
619 Self {
620 a : self.a.floor(),
621 b : self.b.floor(),
622 }
623 }
624 }
625 }
626
627 #[inline]
628 pub fn ceil(self) -> Self {
629 pick! {
630 if #[cfg(target_feature="avx512f")] {
631 Self { avx512: round_m512::<{round_op!(PosInf)}>(self.avx512) }
632 } else {
633 Self {
634 a : self.a.ceil(),
635 b : self.b.ceil(),
636 }
637 }
638 }
639 }
640
641 #[inline]
642 pub fn round(self) -> Self {
643 pick! {
644 if #[cfg(target_feature="avx512f")] {
645 const_f32_as_f32x16!(HALF_NEXT_DOWN, 0.5_f32.next_down());
646 const_f32_as_f32x16!(BOUNDS_LIMIT, 8388608.0);
647
648 let self_abs = self.abs();
649
650 let adjusted_self = self_abs + Self::HALF;
651 let result_abs = Self { avx512: round_m512::<{round_op!(Zero)}>(adjusted_self.avx512) };
652 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
655
656 let bounds_mask: Self = cast(cmp_op_mask_i32_m512i::<{cmp_int_op!(Lt)}>(
658 cast(self_abs),
659 cast(BOUNDS_LIMIT),
660 ));
661
662 bounds_mask.abs().bitselect(result_abs, self)
664 } else {
665 Self {
666 a: self.a.round(),
667 b: self.b.round(),
668 }
669 }
670 }
671 }
672
673 #[inline]
674 pub fn round_int(self) -> i32x16 {
675 pick! {
676 if #[cfg(target_feature="avx512f")] {
677 let non_nan_mask = self.simd_eq(self);
679 let non_nan = self & non_nan_mask;
680 let flip_to_max: i32x16 = cast(self.simd_ge(Self::splat(2147483648.0)));
681 let cast: i32x16 = cast(convert_to_i32_m512i_from_m512(non_nan.avx512));
682 flip_to_max ^ cast
683 } else {
684 i32x16 {
685 a: self.a.round_int(),
686 b: self.b.round_int(),
687 }
688 }
689 }
690 }
691
692 #[inline]
693 pub fn fast_round_int(self) -> i32x16 {
694 pick! {
695 if #[cfg(target_feature="avx512f")] {
696 cast(convert_to_i32_m512i_from_m512(self.avx512))
697 } else {
698 i32x16 {
699 a: self.a.fast_round_int(),
700 b: self.b.fast_round_int(),
701 }
702 }
703 }
704 }
705
706 #[inline]
707 pub fn round_ties_even(self) -> Self {
708 pick! {
709 if #[cfg(target_feature="avx512f")] {
710 Self { avx512: round_m512::<{round_op!(Nearest)}>(self.avx512) }
711 } else {
712 Self {
713 a: self.a.round_ties_even(),
714 b: self.b.round_ties_even(),
715 }
716 }
717 }
718 }
719
720 #[inline]
721 pub fn trunc(self) -> Self {
722 pick! {
723 if #[cfg(target_feature="avx512f")] {
724 Self { avx512: round_m512::<{round_op!(Zero)}>(self.avx512) }
725 } else {
726 Self {
727 a: self.a.trunc(),
728 b: self.b.trunc(),
729 }
730 }
731 }
732 }
733
734 #[inline]
735 pub fn trunc_int(self) -> i32x16 {
736 pick! {
737 if #[cfg(target_feature="avx512f")] {
738 let non_nan_mask = self.simd_eq(self);
740 let non_nan = self & non_nan_mask;
741 let flip_to_max: i32x16 = cast(self.simd_ge(Self::splat(2147483648.0)));
742 let cast: i32x16 = cast(convert_truncate_m512_i32_m512i(non_nan.avx512));
743 flip_to_max ^ cast
744 } else {
745 cast([
746 self.a.trunc_int(),
747 self.b.trunc_int(),
748 ])
749 }
750 }
751 }
752
753 #[inline]
754 pub fn fast_trunc_int(self) -> i32x16 {
755 pick! {
756 if #[cfg(all(target_feature="avx512f"))] {
757 cast(convert_truncate_m512_i32_m512i(self.avx512))
758 } else {
759 cast([
760 self.a.fast_trunc_int(),
761 self.b.fast_trunc_int(),
762 ])
763 }
764 }
765 }
766
767 #[inline]
776 pub fn mul_add(self, a: Self, b: Self) -> Self {
777 pick! {
778 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
779 Self { avx512: fused_mul_add_m512(self.avx512, a.avx512, b.avx512) }
780 } else if #[cfg(target_feature="avx512f")] {
781 (self * a) + b
783 } else {
784 Self {
785 a: self.a.mul_add(a.a, b.a),
786 b: self.b.mul_add(a.b, b.b),
787 }
788 }
789 }
790 }
791
792 #[inline]
801 pub fn mul_sub(self, a: Self, b: Self) -> Self {
802 pick! {
803 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
804 Self { avx512: fused_mul_sub_m512(self.avx512, a.avx512, b.avx512) }
805 } else if #[cfg(target_feature="avx512f")] {
806 (self * a) - b
808 } else {
809 Self {
810 a: self.a.mul_sub(a.a, b.a),
811 b: self.b.mul_sub(a.b, b.b),
812 }
813 }
814 }
815 }
816
817 #[inline]
826 pub fn mul_neg_add(self, a: Self, b: Self) -> Self {
827 pick! {
828 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
829 Self { avx512: fused_mul_neg_add_m512(self.avx512, a.avx512, b.avx512) }
830 } else if #[cfg(target_feature="avx512f")] {
831 b - (self * a)
833 } else {
834 Self {
835 a: self.a.mul_neg_add(a.a, b.a),
836 b: self.b.mul_neg_add(a.b, b.b),
837 }
838 }
839 }
840 }
841
842 #[inline]
851 pub fn mul_neg_sub(self, a: Self, b: Self) -> Self {
852 pick! {
853 if #[cfg(all(target_feature="avx512f",target_feature="fma"))] {
854 Self { avx512: fused_mul_neg_sub_m512(self.avx512, a.avx512, b.avx512) }
855 } else if #[cfg(target_feature="avx512f")] {
856 -(self * a) - b
858 } else {
859 Self {
860 a: self.a.mul_neg_sub(a.a, b.a),
861 b: self.b.mul_neg_sub(a.b, b.b),
862 }
863 }
864 }
865 }
866
867 #[inline]
868 pub fn powf_simd(self, n: Self) -> Self {
869 const_f32_as_f32x16!(ln2f_hi, 0.693359375);
870 const_f32_as_f32x16!(ln2f_lo, -2.12194440e-4);
871 const_f32_as_f32x16!(P0logf, 3.3333331174E-1);
872 const_f32_as_f32x16!(P1logf, -2.4999993993E-1);
873 const_f32_as_f32x16!(P2logf, 2.0000714765E-1);
874 const_f32_as_f32x16!(P3logf, -1.6668057665E-1);
875 const_f32_as_f32x16!(P4logf, 1.4249322787E-1);
876 const_f32_as_f32x16!(P5logf, -1.2420140846E-1);
877 const_f32_as_f32x16!(P6logf, 1.1676998740E-1);
878 const_f32_as_f32x16!(P7logf, -1.1514610310E-1);
879 const_f32_as_f32x16!(P8logf, 7.0376836292E-2);
880
881 const_f32_as_f32x16!(p2expf, 1.0 / 2.0); const_f32_as_f32x16!(p3expf, 1.0 / 6.0);
883 const_f32_as_f32x16!(p4expf, 1.0 / 24.0);
884 const_f32_as_f32x16!(p5expf, 1.0 / 120.0);
885 const_f32_as_f32x16!(p6expf, 1.0 / 720.0);
886 const_f32_as_f32x16!(p7expf, 1.0 / 5040.0);
887
888 let x1 = self.abs();
889 let x = x1.fraction_2();
890 let mask = x.simd_gt(f32x16::SQRT_2 * f32x16::HALF);
891 let x = (!mask).select(x + x, x);
892
893 let x = x - f32x16::ONE;
894 let x2 = x * x;
895 let lg1 = polynomial_8!(
896 x, P0logf, P1logf, P2logf, P3logf, P4logf, P5logf, P6logf, P7logf, P8logf
897 );
898 let lg1 = lg1 * x2 * x;
899
900 let ef = x1.exponent();
901 let ef = mask.select(ef + f32x16::ONE, ef);
902 let e1 = (ef * n).round_ties_even();
903 let yr = ef.mul_sub(n, e1);
904
905 let lg = f32x16::HALF.mul_neg_add(x2, x) + lg1;
906 let x2_err = (f32x16::HALF * x).mul_sub(x, f32x16::HALF * x2);
907 let lg_err = f32x16::HALF.mul_add(x2, lg - x) - lg1;
908
909 let e2 = (lg * n * f32x16::LOG2_E).round_ties_even();
910 let v = lg.mul_sub(n, e2 * ln2f_hi);
911 let v = e2.mul_neg_add(ln2f_lo, v);
912 let v = v - (lg_err + x2_err).mul_sub(n, yr * f32x16::LN_2);
913
914 let x = v;
915 let e3 = (x * f32x16::LOG2_E).round_ties_even();
916 let x = e3.mul_neg_add(f32x16::LN_2, x);
917 let x2 = x * x;
918 let z = x2.mul_add(
919 polynomial_5!(x, p2expf, p3expf, p4expf, p5expf, p6expf, p7expf),
920 x + f32x16::ONE,
921 );
922
923 let ee = e1 + e2 + e3;
924 let ei = cast::<_, i32x16>(ee.round_int());
925 let ej = cast::<_, i32x16>(ei + (cast::<_, i32x16>(z) >> 23));
926
927 let overflow = cast::<_, f32x16>(ej.simd_gt(i32x16::splat(0x0FF)))
928 | (ee.simd_gt(f32x16::splat(300.0)));
929 let underflow = cast::<_, f32x16>(ej.simd_lt(i32x16::splat(0x000)))
930 | (ee.simd_lt(f32x16::splat(-300.0)));
931
932 let z = cast::<_, f32x16>(cast::<_, i32x16>(z) + (ei << 23));
934 let z = underflow.select(f32x16::ZERO, z);
936 let z = overflow.select(Self::infinity(), z);
937
938 let x_zero = self.is_zero_or_subnormal();
940 let z = x_zero.select(
941 n.simd_lt(f32x16::ZERO).select(
942 Self::infinity(),
943 n.simd_eq(f32x16::ZERO).select(f32x16::ONE, f32x16::ZERO),
944 ),
945 z,
946 );
947
948 let x_sign = self.is_sign_negative();
949 let z = if x_sign.any() {
950 let yi = n.simd_eq(n.round_ties_even());
952
953 let y_odd = cast::<i32x16, f32x16>(n.round_int() << 31);
955
956 let z1 = yi
957 .select(z | y_odd, self.simd_eq(Self::ZERO).select(z, Self::nan_pow()));
958
959 x_sign.select(z1, z)
960 } else {
961 z
962 };
963
964 let x_finite = self.is_finite();
965 let y_finite = n.is_finite();
966 let e_finite = ee.is_finite();
967 if (x_finite & y_finite & (e_finite | x_zero)).all() {
968 return z;
969 }
970
971 (self.is_nan() | n.is_nan()).select(self + n, z)
972 }
973
974 #[inline]
975 pub fn sqrt(self) -> Self {
976 pick! {
977 if #[cfg(target_feature="avx512f")] {
978 Self { avx512: sqrt_m512(self.avx512) }
979 } else {
980 Self {
981 a : self.a.sqrt(),
982 b : self.b.sqrt(),
983 }
984 }
985 }
986 }
987
988 #[inline]
990 pub fn exp(self) -> Self {
991 const_f32_as_f32x16!(P0, 1.0 / 2.0);
992 const_f32_as_f32x16!(P1, 1.0 / 6.0);
993 const_f32_as_f32x16!(P2, 1.0 / 24.0);
994 const_f32_as_f32x16!(P3, 1.0 / 120.0);
995 const_f32_as_f32x16!(P4, 1.0 / 720.0);
996 const_f32_as_f32x16!(P5, 1.0 / 5040.0);
997 const_f32_as_f32x16!(LN2D_HI, 0.693359375);
1004 const_f32_as_f32x16!(LN2D_LO, -2.12194440e-4);
1005 let max_x = f32x16::from(88.723);
1008 let min_x = f32x16::from(-103.63);
1009 let finite = self.is_finite();
1011 let neg_underflow = self.simd_lt(min_x) & finite;
1012 if neg_underflow.all() {
1013 return Self::ZERO;
1014 }
1015 let max_r = f32x16::from(127.0);
1016 let r = (self * Self::LOG2_E).round_ties_even();
1017 let big = r.simd_gt(max_r);
1018 let r_safe = big.select(max_r, r);
1019 let excess = r - max_r;
1020 let excess = big.select(excess, Self::ZERO);
1021 let scale = Self::vm_pow2n(excess);
1022 let x = r.mul_neg_add(LN2D_HI, self);
1023 let x = r.mul_neg_add(LN2D_LO, x);
1024 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1025 let x2 = x * x;
1026 let z = z.mul_add(x2, x);
1027 let n2 = Self::vm_pow2n(r_safe);
1028 let z = (z + Self::ONE) * scale * n2;
1029 let nan_mask = self.is_nan();
1030 let mut result = nan_mask.select(Self::nan_pow(), z);
1031 let pos_overflow = self.simd_gt(max_x) & finite;
1032 result = pos_overflow.select(Self::infinity(), result);
1033 result = neg_underflow.select(Self::ZERO, result);
1034 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1035 result = pos_inf.select(Self::infinity(), result);
1036 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1037 result = neg_inf.select(Self::ZERO, result);
1038 result
1039 }
1040
1041 #[inline]
1042 pub fn exp2(self) -> Self {
1043 const_f32_as_f32x16!(P2, 1.0 / 2.0);
1044 const_f32_as_f32x16!(P3, 1.0 / 6.0);
1045 const_f32_as_f32x16!(P4, 1.0 / 24.0);
1046 const_f32_as_f32x16!(P5, 1.0 / 120.0);
1047 const_f32_as_f32x16!(P6, 1.0 / 720.0);
1048 const_f32_as_f32x16!(P7, 1.0 / 5040.0);
1049
1050 let max_x = f32x16::from(127.99999);
1053 let min_x = f32x16::from(-149.5);
1054 let finite = self.is_finite();
1055 let neg_underflow = self.simd_lt(min_x) & finite;
1056 if neg_underflow.all() {
1057 return Self::ZERO;
1058 }
1059
1060 let round = self.round_ties_even();
1061 let max_r = f32x16::from(127.0);
1062 let big = round.simd_gt(max_r);
1063 let r_safe = big.select(max_r, round);
1064 let excess = round - max_r;
1065 let excess = big.select(excess, Self::ZERO);
1066 let scale = Self::vm_pow2n(excess);
1067
1068 let fract = (self - round) * Self::LN_2;
1069 let fract_partial_exp2 = polynomial_5!(fract, P2, P3, P4, P5, P6, P7);
1070 let fract2 = fract * fract;
1071 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1072
1073 let n2 = Self::vm_pow2n(r_safe);
1074 let result = fract_exp2 * scale * n2;
1075
1076 let nan_mask = self.is_nan();
1077 let mut result = nan_mask.select(Self::nan_pow(), result);
1078 let pos_overflow = self.simd_gt(max_x) & finite;
1079 result = pos_overflow.select(Self::infinity(), result);
1080 result = neg_underflow.select(Self::ZERO, result);
1081 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1082 result = pos_inf.select(Self::infinity(), result);
1083 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1084 result = neg_inf.select(Self::ZERO, result);
1085 result
1086 }
1087
1088 #[inline]
1089 pub fn ln(self) -> Self {
1090 const_f32_as_f32x16!(HALF, 0.5);
1091 const_f32_as_f32x16!(P0, 3.3333331174E-1);
1092 const_f32_as_f32x16!(P1, -2.4999993993E-1);
1093 const_f32_as_f32x16!(P2, 2.0000714765E-1);
1094 const_f32_as_f32x16!(P3, -1.6668057665E-1);
1095 const_f32_as_f32x16!(P4, 1.4249322787E-1);
1096 const_f32_as_f32x16!(P5, -1.2420140846E-1);
1097 const_f32_as_f32x16!(P6, 1.1676998740E-1);
1098 const_f32_as_f32x16!(P7, -1.1514610310E-1);
1099 const_f32_as_f32x16!(P8, 7.0376836292E-2);
1100 const_f32_as_f32x16!(LN2F_HI, 0.693359375);
1101 const_f32_as_f32x16!(LN2F_LO, -2.12194440e-4);
1102 const_f32_as_f32x16!(VM_SMALLEST_NORMAL, 1.17549435E-38);
1103
1104 let x1 = self;
1105 let x = Self::fraction_2(x1);
1106 let e = Self::exponent(x1);
1107 let mask = x.simd_gt(Self::SQRT_2 * HALF);
1108 let x = (!mask).select(x + x, x);
1109 let fe = mask.select(e + Self::ONE, e);
1110 let x = x - Self::ONE;
1111 let res = polynomial_8!(x, P0, P1, P2, P3, P4, P5, P6, P7, P8);
1112 let x2 = x * x;
1113 let res = x2 * x * res;
1114 let res = fe.mul_add(LN2F_LO, res);
1115 let res = res + x2.mul_neg_add(HALF, x);
1116 let res = fe.mul_add(LN2F_HI, res);
1117 let overflow = !self.is_finite();
1118 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1119 let mask = overflow | underflow;
1120 if !mask.any() {
1121 res
1122 } else {
1123 let is_zero = self.is_zero_or_subnormal();
1124 let res = underflow.select(Self::nan_log(), res);
1125 let res = is_zero.select(-Self::infinity(), res);
1130 let res = overflow.select(self, res);
1131 let res = (!self.is_finite() & self.is_sign_negative())
1133 .select(Self::nan_log(), res);
1134 res
1135 }
1136 }
1137
1138 #[inline]
1139 pub fn cbrt(self) -> Self {
1140 let a = self.abs();
1141 let zero = a.simd_eq(Self::ZERO);
1142 if zero.all() {
1143 return self; }
1145 let inf = a.is_inf();
1146 let nan = self.is_nan();
1147
1148 let tiny = a.simd_lt(Self::from(f32::MIN_POSITIVE));
1149 let a_work = tiny.select(a * Self::from(16777216.0), a);
1150
1151 let e = Self::exponent(a_work) + Self::ONE;
1152 let d = Self::fraction_2(a_work);
1153
1154 const_f32_as_f32x16!(C0, 2.2241257);
1161 const_f32_as_f32x16!(C1, -3.8095417);
1162 const_f32_as_f32x16!(C2, 5.8982625);
1163 const_f32_as_f32x16!(C3, -5.532182);
1164 const_f32_as_f32x16!(C4, 2.8208892);
1165 const_f32_as_f32x16!(C5, -0.60156447);
1166 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1167
1168 let x2 = x * x;
1169 let x4 = x2 * x2;
1170 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1171 let mut y = (d * x) * x;
1173 let yx = y * x;
1174 let t = Self::from(2.0 / 3.0);
1175 y = y - t * y * (yx - Self::ONE);
1176
1177 let three = Self::from(3.0);
1179 let two = Self::from(2.0);
1180 let neg = e.simd_lt(Self::ZERO);
1181 let e_adj = neg.select(e - two, e);
1182 let k = (e_adj / three).trunc();
1183 let r = e - three * k;
1184 const_f32_as_f32x16!(CBRT2, 1.259921);
1185 const_f32_as_f32x16!(CBRT4, 1.587401);
1186 y = r.simd_eq(Self::ONE).select(y * CBRT2, y);
1187 y = r.simd_eq(two).select(y * CBRT4, y);
1188 y *= Self::vm_pow2n(k);
1189 y = tiny.select(y / Self::from(256.0_f32), y);
1190
1191 let result = y.flip_signs(self);
1192 let result = nan.select(self, result);
1193 let result = zero.select(self, result);
1194 let result = inf.select(self, result);
1195 result
1196 }
1197
1198 #[inline]
1199 pub fn asin(self) -> Self {
1200 const_f32_as_f32x16!(P4asinf, 4.2163199048E-2);
1203 const_f32_as_f32x16!(P3asinf, 2.4181311049E-2);
1204 const_f32_as_f32x16!(P2asinf, 4.5470025998E-2);
1205 const_f32_as_f32x16!(P1asinf, 7.4953002686E-2);
1206 const_f32_as_f32x16!(P0asinf, 1.6666752422E-1);
1207
1208 let xa = self.abs();
1209 let big = xa.simd_ge(f32x16::splat(0.5));
1210
1211 let x1 = f32x16::splat(0.5) * (f32x16::ONE - xa);
1212 let x2 = xa * xa;
1213 let x3 = big.select(x1, x2);
1214
1215 let xb = x1.sqrt();
1216
1217 let x4 = big.select(xb, xa);
1218
1219 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1220 let z = z.mul_add(x3 * x4, x4);
1221
1222 let z1 = z + z;
1223
1224 let z3 = f32x16::FRAC_PI_2 - z1;
1226 let asin = big.select(z3, z);
1227 let asin = asin.flip_signs(self);
1228
1229 asin
1230 }
1231
1232 #[inline]
1233 pub fn acos(self) -> Self {
1234 const_f32_as_f32x16!(P4asinf, 4.2163199048E-2);
1237 const_f32_as_f32x16!(P3asinf, 2.4181311049E-2);
1238 const_f32_as_f32x16!(P2asinf, 4.5470025998E-2);
1239 const_f32_as_f32x16!(P1asinf, 7.4953002686E-2);
1240 const_f32_as_f32x16!(P0asinf, 1.6666752422E-1);
1241
1242 let xa = self.abs();
1243 let big = xa.simd_ge(f32x16::splat(0.5));
1244
1245 let x1 = f32x16::splat(0.5) * (f32x16::ONE - xa);
1246 let x2 = xa * xa;
1247 let x3 = big.select(x1, x2);
1248
1249 let xb = x1.sqrt();
1250
1251 let x4 = big.select(xb, xa);
1252
1253 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1254 let z = z.mul_add(x3 * x4, x4);
1255
1256 let z1 = z + z;
1257
1258 let z3 = self.simd_lt(f32x16::ZERO).select(f32x16::PI - z1, z1);
1260 let z4 = f32x16::FRAC_PI_2 - z.flip_signs(self);
1261 let acos = big.select(z3, z4);
1262
1263 acos
1264 }
1265
1266 #[inline]
1267 pub fn atan(self) -> Self {
1268 const_f32_as_f32x16!(P3atanf, 8.05374449538E-2);
1271 const_f32_as_f32x16!(P2atanf, -1.38776856032E-1);
1272 const_f32_as_f32x16!(P1atanf, 1.99777106478E-1);
1273 const_f32_as_f32x16!(P0atanf, -3.33329491539E-1);
1274
1275 let t = self.abs();
1276
1277 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1281 let notbig = t.simd_le(Self::SQRT_2 + Self::ONE);
1282
1283 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1284 s = notsmal & s;
1285
1286 let mut a = notbig & t;
1287 a = notsmal.select(a - Self::ONE, a);
1288 let mut b = notbig & Self::ONE;
1289 b = notsmal.select(b + t, b);
1290 let z = a / b;
1291
1292 let zz = z * z;
1293
1294 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1296 re = re.mul_add(zz * z, z) + s;
1297
1298 re = (self.is_sign_negative()).select(-re, re);
1300
1301 re
1302 }
1303
1304 #[inline]
1305 pub fn atan2(self, x: Self) -> Self {
1306 const_f32_as_f32x16!(P3atanf, 8.05374449538E-2);
1309 const_f32_as_f32x16!(P2atanf, -1.38776856032E-1);
1310 const_f32_as_f32x16!(P1atanf, 1.99777106478E-1);
1311 const_f32_as_f32x16!(P0atanf, -3.33329491539E-1);
1312
1313 let y = self;
1314
1315 let x1 = x.abs();
1317 let y1 = y.abs();
1318 let swapxy = y1.simd_gt(x1);
1319 let mut x2 = swapxy.select(y1, x1);
1321 let mut y2 = swapxy.select(x1, y1);
1322
1323 let both_infinite = x.is_inf() & y.is_inf();
1325 if both_infinite.any() {
1326 let minus_one = -Self::ONE;
1327 x2 = both_infinite.select(x2 & minus_one, x2);
1328 y2 = both_infinite.select(y2 & minus_one, y2);
1329 }
1330
1331 let t = y2 / x2;
1333
1334 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1337
1338 let a = notsmal.select(t - Self::ONE, t);
1339 let b = notsmal.select(t + Self::ONE, Self::ONE);
1340 let s = notsmal & Self::FRAC_PI_4;
1341 let z = a / b;
1342
1343 let zz = z * z;
1344
1345 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1347 re = re.mul_add(zz * z, z) + s;
1348
1349 re = swapxy.select(Self::FRAC_PI_2 - re, re);
1351 re = ((x | y).simd_eq(Self::ZERO)).select(Self::ZERO, re);
1352 re = (x.is_sign_negative()).select(Self::PI - re, re);
1353
1354 re = (y.is_sign_negative()).select(-re, re);
1356
1357 re
1358 }
1359
1360 #[inline]
1361 pub fn sin_cos(self) -> (Self, Self) {
1362 const_f32_as_f32x16!(DP1F, 0.78515625_f32 * 2.0);
1366 const_f32_as_f32x16!(DP2F, 2.4187564849853515625E-4_f32 * 2.0);
1367 const_f32_as_f32x16!(DP3F, 3.77489497744594108E-8_f32 * 2.0);
1368
1369 const_f32_as_f32x16!(P0sinf, -1.6666654611E-1);
1370 const_f32_as_f32x16!(P1sinf, 8.3321608736E-3);
1371 const_f32_as_f32x16!(P2sinf, -1.9515295891E-4);
1372
1373 const_f32_as_f32x16!(P0cosf, 4.166664568298827E-2);
1374 const_f32_as_f32x16!(P1cosf, -1.388731625493765E-3);
1375 const_f32_as_f32x16!(P2cosf, 2.443315711809948E-5);
1376
1377 const_f32_as_f32x16!(TWO_OVER_PI, 2.0 / core::f32::consts::PI);
1378
1379 let xa = self.abs();
1380
1381 let y = (xa * TWO_OVER_PI).round_ties_even();
1383 let q: i32x16 = y.round_int();
1384
1385 let x = y.mul_neg_add(DP3F, y.mul_neg_add(DP2F, y.mul_neg_add(DP1F, xa)));
1386
1387 let x2 = x * x;
1388 let mut s = polynomial_2!(x2, P0sinf, P1sinf, P2sinf) * (x * x2) + x;
1389 let mut c = polynomial_2!(x2, P0cosf, P1cosf, P2cosf) * (x2 * x2)
1390 + f32x16::from(0.5).mul_neg_add(x2, f32x16::from(1.0));
1391
1392 let swap = !(q & i32x16::from(1)).simd_eq(i32x16::from(0));
1393
1394 let mut overflow: f32x16 = cast(q.simd_gt(i32x16::from(0x2000000)));
1395 overflow &= xa.is_finite();
1396 s = overflow.select(f32x16::from(0.0), s);
1397 c = overflow.select(f32x16::from(1.0), c);
1398
1399 let mut sin1 = cast::<_, f32x16>(swap).select(c, s);
1401 let sign_sin: i32x16 = (q << 30) ^ cast::<_, i32x16>(self);
1402 sin1 = sin1.flip_signs(cast(sign_sin));
1403
1404 let mut cos1 = cast::<_, f32x16>(swap).select(s, c);
1406 let sign_cos: i32x16 = ((q + i32x16::from(1)) & i32x16::from(2)) << 30;
1407 cos1 ^= cast::<_, f32x16>(sign_cos);
1408
1409 let finite = self.is_finite();
1411 let nan = Self::splat(f32::NAN);
1412 let sin_final = finite.select(sin1, nan);
1413 let cos_final = finite.select(cos1, nan);
1414
1415 (sin_final, cos_final)
1416 }
1417
1418 #[inline]
1419 pub fn asin_acos(self) -> (Self, Self) {
1420 const_f32_as_f32x16!(P4asinf, 4.2163199048E-2);
1423 const_f32_as_f32x16!(P3asinf, 2.4181311049E-2);
1424 const_f32_as_f32x16!(P2asinf, 4.5470025998E-2);
1425 const_f32_as_f32x16!(P1asinf, 7.4953002686E-2);
1426 const_f32_as_f32x16!(P0asinf, 1.6666752422E-1);
1427
1428 let xa = self.abs();
1429 let big = xa.simd_ge(f32x16::splat(0.5));
1430
1431 let x1 = f32x16::splat(0.5) * (f32x16::ONE - xa);
1432 let x2 = xa * xa;
1433 let x3 = big.select(x1, x2);
1434
1435 let xb = x1.sqrt();
1436
1437 let x4 = big.select(xb, xa);
1438
1439 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1440 let z = z.mul_add(x3 * x4, x4);
1441
1442 let z1 = z + z;
1443
1444 let z3 = self.simd_lt(f32x16::ZERO).select(f32x16::PI - z1, z1);
1446 let z4 = f32x16::FRAC_PI_2 - z.flip_signs(self);
1447 let acos = big.select(z3, z4);
1448
1449 let z3 = f32x16::FRAC_PI_2 - z1;
1451 let asin = big.select(z3, z);
1452 let asin = asin.flip_signs(self);
1453
1454 (asin, acos)
1455 }
1456
1457 #[inline]
1458 pub fn exp_m1(self) -> Self {
1459 if self.simd_lt(f32x16::from(-17.329)).all() {
1463 return f32x16::from(-1.0);
1464 }
1465 const_f32_as_f32x16!(P0, 1.0 / 2.0);
1466 const_f32_as_f32x16!(P1, 1.0 / 6.0);
1467 const_f32_as_f32x16!(P2, 1.0 / 24.0);
1468 const_f32_as_f32x16!(P3, 1.0 / 120.0);
1469 const_f32_as_f32x16!(P4, 1.0 / 720.0);
1470 const_f32_as_f32x16!(P5, 1.0 / 5040.0);
1471 const_f32_as_f32x16!(LN2D_HI, 0.693359375);
1478 const_f32_as_f32x16!(LN2D_LO, -2.12194440e-4);
1479 let max_x = f32x16::from(88.723);
1482 let min_x = f32x16::from(-103.63);
1483 let max_r = f32x16::from(127.0);
1484 let r = (self * Self::LOG2_E).round_ties_even();
1485 let big = r.simd_gt(max_r);
1486 let r_safe = big.select(max_r, r);
1487 let excess = r - max_r;
1488 let excess = big.select(excess, Self::ZERO);
1489 let scale = Self::vm_pow2n(excess);
1490 let x = r.mul_neg_add(LN2D_HI, self);
1491 let x = r.mul_neg_add(LN2D_LO, x);
1492 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1493 let x2 = x * x;
1494 let z = z.mul_add(x2, x);
1495 let n2 = Self::vm_pow2n(r_safe);
1496 let exp_val = (z + Self::ONE) * scale * n2;
1497 let r_is_zero = r.simd_eq(Self::ZERO);
1498 let z = r_is_zero.select(z, exp_val - Self::ONE);
1499 let nan_mask = self.is_nan();
1500 let finite = self.is_finite();
1501 let mut result = nan_mask.select(Self::nan_pow(), z);
1502 let pos_overflow = self.simd_gt(max_x) & finite;
1503 result = pos_overflow.select(Self::infinity(), result);
1504 let neg_underflow = self.simd_lt(min_x) & finite;
1505 result = neg_underflow.select(-Self::ONE, result);
1506 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1507 result = pos_inf.select(Self::infinity(), result);
1508 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1509 result = neg_inf.select(-Self::ONE, result);
1510 let is_zero = self.simd_eq(Self::ZERO);
1511 result = is_zero.select(self, result);
1512 result
1513 }
1514
1515 #[inline]
1516 pub fn ln_1p(self) -> Self {
1517 let u = self + Self::ONE;
1525 let eq = u.simd_eq(Self::ONE);
1526 let ln_u = Self::ln(u);
1527 let correction = self * (ln_u / (u - Self::ONE));
1528 let result = eq.select(self, correction);
1529 let over = u.is_inf();
1530 over.select(ln_u, result)
1531 }
1532
1533 #[inline]
1534 pub fn sinh(self) -> Self {
1535 const_f32_as_f32x16!(P0, 1.0);
1536 const_f32_as_f32x16!(P1, 1.0 / 6.0);
1537 const_f32_as_f32x16!(P2, 1.0 / 120.0);
1538 const_f32_as_f32x16!(P3, 1.0 / 5040.0);
1539 let a = self.abs();
1540 let small = a.simd_lt(f32x16::from(0.5));
1542 let t = a * a;
1543 let poly = a * polynomial_3!(t, P0, P1, P2, P3);
1544 let exp_based = {
1545 let e = a.exp();
1546 (e - Self::ONE / e) * Self::HALF
1547 };
1548 let result = small.select(poly, exp_based);
1549 result.flip_signs(self)
1550 }
1551
1552 #[inline]
1553 pub fn cosh(self) -> Self {
1554 const_f32_as_f32x16!(P0, 1.0);
1555 const_f32_as_f32x16!(P1, 1.0 / 2.0);
1556 const_f32_as_f32x16!(P2, 1.0 / 24.0);
1557 const_f32_as_f32x16!(P3, 1.0 / 720.0);
1558 let a = self.abs();
1559 let small = a.simd_lt(f32x16::from(0.5));
1561 let t = a * a;
1562 let poly = polynomial_3!(t, P0, P1, P2, P3);
1563 let exp_based = {
1564 let e = a.exp();
1565 (e + Self::ONE / e) * Self::HALF
1566 };
1567 small.select(poly, exp_based)
1568 }
1569
1570 #[inline]
1571 pub fn tanh(self) -> Self {
1572 let a = self.abs();
1576 let large = a.simd_gt(f32x16::from(9.011));
1577 if large.all() {
1578 return Self::ONE.flip_signs(self);
1579 }
1580 let small = a.simd_lt(f32x16::from(2e-4));
1581 let exp_based = {
1582 let t = (Self::from(-2.0) * a).exp_m1();
1583 let pos = -t / (t + Self::from(2.0));
1584 pos.flip_signs(self)
1585 };
1586 let result = small.select(self, exp_based);
1587 large.select(Self::ONE.flip_signs(self), result)
1588 }
1589}
1590
1591impl f32x16 {
1594 #[inline]
1595 fn vm_pow2n(self) -> Self {
1596 const_f32_as_f32x16!(pow2_23, 8388608.0);
1597 const_f32_as_f32x16!(bias, 127.0);
1598 let a = self + (bias + pow2_23);
1599 let c = cast::<_, i32x16>(a) << 23;
1600 let std_result = cast::<_, f32x16>(c);
1601
1602 let min_exp = f32x16::from(-126.0);
1603 let is_sub = self.simd_lt(min_exp);
1604 if is_sub.any() {
1605 let valid = self.simd_ge(f32x16::from(-149.0));
1606 let shift_f = self + f32x16::from(149.0);
1607 let mut shift_i = shift_f.trunc_int();
1608 shift_i = cast::<_, i32x16>(valid).select(shift_i, i32x16::ZERO);
1609 let mantissa = i32x16::ONE << shift_i;
1610 let sub_result = cast::<_, f32x16>(mantissa);
1611 let sub_result = valid.select(sub_result, f32x16::ZERO);
1612 is_sub.select(sub_result, std_result)
1613 } else {
1614 std_result
1615 }
1616 }
1617
1618 #[inline]
1619 fn exponent(self) -> Self {
1620 const_f32_as_f32x16!(pow2_23, 8388608.0);
1621 const_f32_as_f32x16!(bias, 127.0);
1622 let a = cast::<_, u32x16>(self);
1623 let b = a >> 23;
1624 let c = b | cast::<_, u32x16>(pow2_23);
1625 let d = cast::<_, f32x16>(c);
1626 let e = d - (pow2_23 + bias);
1627 e
1628 }
1629
1630 #[inline]
1631 fn fraction_2(self) -> Self {
1632 let t1 = cast::<_, u32x16>(self);
1633 let t2 = cast::<_, u32x16>(
1634 (t1 & u32x16::from(0x007FFFFF)) | u32x16::from(0x3F000000),
1635 );
1636 cast::<_, f32x16>(t2)
1637 }
1638
1639 #[inline]
1640 fn is_zero_or_subnormal(self) -> Self {
1641 let t = cast::<_, i32x16>(self);
1642 let t = t & i32x16::splat(0x7F800000);
1643 let mask = t.simd_eq(i32x16::splat(0));
1644 cast::<_, f32x16>(mask)
1645 }
1646
1647 #[inline]
1648 fn infinity() -> Self {
1649 cast::<_, f32x16>(i32x16::splat(0x7F800000))
1650 }
1651
1652 #[inline]
1653 fn nan_log() -> Self {
1654 cast::<_, f32x16>(i32x16::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1655 }
1656
1657 #[inline]
1658 fn nan_pow() -> Self {
1659 cast::<_, f32x16>(i32x16::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1660 }
1661
1662 #[inline]
1664 pub fn from_i32x16(v: i32x16) -> Self {
1665 pick! {
1666 if #[cfg(target_feature="avx512f")] {
1667 Self { avx512: convert_to_m512_from_i32_m512i(v.avx512) }
1668 } else {
1669 Self {
1670 a: f32x8::from_i32x8(v.a),
1671 b: f32x8::from_i32x8(v.b),
1672 }
1673 }
1674 }
1675 }
1676
1677 #[inline]
1687 #[must_use]
1688 #[deprecated(since = "1.4.0", note = "renamed to `is_sign_negative`")]
1689 pub fn sign_bit(self) -> Self {
1690 self.is_sign_negative()
1691 }
1692}