1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx")] {
5 #[derive(Default, Clone, Copy, PartialEq)]
12 #[repr(C, align(32))]
13 pub struct f32x8 { pub(crate) avx: m256 }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq)]
22 #[repr(C, align(32))]
23 pub struct f32x8 { pub(crate) a : f32x4, pub(crate) b : f32x4 }
24 }
25}
26
27macro_rules! const_f32_as_f32x8 {
28 ($i:ident, $f:expr) => {
29 #[allow(non_upper_case_globals)]
30 pub const $i: f32x8 = f32x8::new([$f; 8]);
31 };
32}
33
34impl_simd_float! {
35 unsafe {
36 T = f32,
37 N = 8,
38 Simd = f32x8,
39 IntSimd = i32x8,
40 UintT = u32,
41 UintSimd = u32x8,
42 optional_type_x86_inner { X86Inner = __m256 },
43 optional_type_arm_inner {},
44 optional_type_wasm_inner {},
45 }
46 old_powf_simd_fn_name = pow_f32x8,
47
48 #[inline]
49 fn neg(self) -> Self::Output {
50 pick! {
51 if #[cfg(target_feature="avx")] {
52 Self { avx: bitxor_m256(self.avx, Self::splat(-0.0).avx) }
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 {
64 pick! {
65 if #[cfg(target_feature="avx")] {
66 Self { avx: self.avx.not() }
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="avx")] {
80 Self { avx: add_m256(self.avx, rhs.avx) }
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="avx")] {
94 Self { avx: sub_m256(self.avx, rhs.avx) }
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="avx")] {
108 Self { avx: mul_m256(self.avx, rhs.avx) }
109 } else {
110 Self {
111 a : self.a.mul(rhs.a),
112 b : self.b.mul(rhs.b),
113 }
114 }
115 }
116 }
117
118 #[inline]
119 fn div(self, rhs: Self) -> Self::Output {
120 pick! {
121 if #[cfg(target_feature="avx")] {
122 Self { avx: div_m256(self.avx, rhs.avx) }
123 } else {
124 Self {
125 a : self.a.div(rhs.a),
126 b : self.b.div(rhs.b),
127 }
128 }
129 }
130 }
131
132 #[inline]
133 fn rem(self, rhs: Self) -> Self::Output {
134 Self::new([
135 self.to_array()[0] % rhs.to_array()[0],
136 self.to_array()[1] % rhs.to_array()[1],
137 self.to_array()[2] % rhs.to_array()[2],
138 self.to_array()[3] % rhs.to_array()[3],
139 self.to_array()[4] % rhs.to_array()[4],
140 self.to_array()[5] % rhs.to_array()[5],
141 self.to_array()[6] % rhs.to_array()[6],
142 self.to_array()[7] % rhs.to_array()[7],
143 ])
144 }
145
146 #[inline]
147 fn bitand(self, rhs: Self) -> Self::Output {
148 pick! {
149 if #[cfg(target_feature="avx")] {
150 Self { avx: bitand_m256(self.avx, rhs.avx) }
151 } else {
152 Self {
153 a : self.a.bitand(rhs.a),
154 b : self.b.bitand(rhs.b),
155 }
156 }
157 }
158 }
159
160 #[inline]
161 fn bitor(self, rhs: Self) -> Self::Output {
162 pick! {
163 if #[cfg(target_feature="avx")] {
164 Self { avx: bitor_m256(self.avx, rhs.avx) }
165 } else {
166 Self {
167 a : self.a.bitor(rhs.a),
168 b : self.b.bitor(rhs.b),
169 }
170 }
171 }
172 }
173
174 #[inline]
175 fn bitxor(self, rhs: Self) -> Self::Output {
176 pick! {
177 if #[cfg(target_feature="avx")] {
178 Self { avx: bitxor_m256(self.avx, rhs.avx) }
179 } else {
180 Self {
181 a : self.a.bitxor(rhs.a),
182 b : self.b.bitxor(rhs.b),
183 }
184 }
185 }
186 }
187
188 #[inline]
189 fn simd_eq(self, rhs: Self) -> Self::Output {
190 pick! {
191 if #[cfg(target_feature="avx")] {
192 Self { avx: cmp_op_mask_m256::<{cmp_op!(EqualOrdered)}>(self.avx, rhs.avx) }
193 } else {
194 Self {
195 a : self.a.simd_eq(rhs.a),
196 b : self.b.simd_eq(rhs.b),
197 }
198 }
199 }
200 }
201
202 #[inline]
203 fn simd_ne(self, rhs: Self) -> Self::Output {
204 pick! {
205 if #[cfg(target_feature="avx")] {
206 Self { avx: cmp_op_mask_m256::<{cmp_op!(NotEqualUnordered)}>(self.avx, rhs.avx) }
207 } else {
208 Self {
209 a : self.a.simd_ne(rhs.a),
210 b : self.b.simd_ne(rhs.b),
211 }
212 }
213 }
214 }
215
216 #[inline]
217 fn simd_lt(self, rhs: Self) -> Self::Output {
218 pick! {
219 if #[cfg(target_feature="avx")] {
220 Self { avx: cmp_op_mask_m256::<{cmp_op!(LessThanOrdered)}>(self.avx, rhs.avx) }
221 } else {
222 Self {
223 a : self.a.simd_lt(rhs.a),
224 b : self.b.simd_lt(rhs.b),
225 }
226 }
227 }
228 }
229
230 #[inline]
231 fn simd_gt(self, rhs: Self) -> Self::Output {
232 pick! {
233 if #[cfg(target_feature="avx")] {
234 Self { avx: cmp_op_mask_m256::<{cmp_op!(GreaterThanOrdered)}>(self.avx, rhs.avx) }
235 } else {
236 Self {
237 a : self.a.simd_gt(rhs.a),
238 b : self.b.simd_gt(rhs.b),
239 }
240 }
241 }
242 }
243
244 #[inline]
245 fn simd_le(self, rhs: Self) -> Self::Output {
246 pick! {
247 if #[cfg(target_feature="avx")] {
248 Self { avx: cmp_op_mask_m256::<{cmp_op!(LessEqualOrdered)}>(self.avx, rhs.avx) }
249 } else {
250 Self {
251 a : self.a.simd_le(rhs.a),
252 b : self.b.simd_le(rhs.b),
253 }
254 }
255 }
256 }
257
258 #[inline]
259 fn simd_ge(self, rhs: Self) -> Self::Output {
260 pick! {
261 if #[cfg(target_feature="avx")] {
262 Self { avx: cmp_op_mask_m256::<{cmp_op!(GreaterEqualOrdered)}>(self.avx, rhs.avx) }
263 } else {
264 Self {
265 a : self.a.simd_ge(rhs.a),
266 b : self.b.simd_ge(rhs.b),
267 }
268 }
269 }
270 }
271
272 #[inline]
273 pub fn reduce_add(self) -> f32 {
274 pick! {
275 if #[cfg(target_feature="avx")]{
277 let hi_quad = extract_m128_from_m256::<1>(self.avx);
278 let lo_quad = cast_to_m128_from_m256(self.avx);
279 let sum_quad = add_m128(lo_quad,hi_quad);
280 let lo_dual = sum_quad;
281 let hi_dual = move_high_low_m128(sum_quad,sum_quad);
282 let sum_dual = add_m128(lo_dual,hi_dual);
283 let lo = sum_dual;
284 let hi = shuffle_abi_f32_all_m128::<0b_01>(sum_dual, sum_dual);
285 let sum = add_m128_s(lo, hi);
286 get_f32_from_m128_s(sum)
287 } else {
288 self.a.reduce_add() + self.b.reduce_add()
289 }
290 }
291 }
292
293 #[inline]
294 pub fn reduce_mul(self) -> f32 {
295 pick! {
296 if #[cfg(target_feature="avx")] {
298 let hi_quad = extract_m128_from_m256::<1>(self.avx);
299 let lo_quad = cast_to_m128_from_m256(self.avx);
300 let product_quad = mul_m128(lo_quad,hi_quad);
301 let lo_dual = product_quad;
302 let hi_dual = move_high_low_m128(product_quad, product_quad);
303 let product_dual = mul_m128(lo_dual,hi_dual);
304 let lo = product_dual;
305 let hi = shuffle_abi_f32_all_m128::<0b_01>(product_dual, product_dual);
306 let product = mul_m128_s(lo, hi);
307 get_f32_from_m128_s(product)
308 } else {
309 self.a.reduce_mul() * self.b.reduce_mul()
310 }
311 }
312 }
313
314 #[inline]
315 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
316 pick! {
317 if #[cfg(target_feature="avx")] {
318 Self {
319 avx: bitor_m256(
320 bitand_m256(if_one.avx, self.avx),
321 bitandnot_m256(self.avx, if_zero.avx),
322 ),
323 }
324 } else {
325 Self {
326 a: self.a.bitselect(if_one.a, if_zero.a),
327 b: self.b.bitselect(if_one.b, if_zero.b),
328 }
329 }
330 }
331 }
332
333 #[inline]
334 fn select(self, if_true: Self, if_false: Self) -> Self {
335 pick! {
336 if #[cfg(target_feature="avx")] {
337 Self { avx: blend_varying_m256(if_false.avx, if_true.avx, self.avx) }
338 } else {
339 Self {
340 a : self.a.select(if_true.a, if_false.a),
341 b : self.b.select(if_true.b, if_false.b),
342 }
343 }
344 }
345 }
346
347 #[inline]
348 pub fn to_bitmask(self) -> u32 {
349 pick! {
350 if #[cfg(target_feature="avx")] {
351 move_mask_m256(self.avx) as u32
352 } else {
353 (self.b.to_bitmask() << 4) | self.a.to_bitmask()
354 }
355 }
356 }
357
358 #[inline]
359 pub fn any(self) -> bool {
360 pick! {
361 if #[cfg(target_feature="avx")] {
362 move_mask_m256(self.avx) != 0
363 } else {
364 self.a.any() || self.b.any()
365 }
366 }
367 }
368
369 #[inline]
370 pub fn all(self) -> bool {
371 pick! {
372 if #[cfg(target_feature="avx")] {
373 move_mask_m256(self.avx) == 0b11111111
374 } else {
375 self.a.all() && self.b.all()
376 }
377 }
378 }
379
380 #[inline]
383 pub fn transpose(data: [f32x8; 8]) -> [f32x8; 8] {
384 pick! {
385 if #[cfg(target_feature="avx")] {
386 let a0 = unpack_lo_m256(data[0].avx, data[1].avx);
387 let a1 = unpack_hi_m256(data[0].avx, data[1].avx);
388 let a2 = unpack_lo_m256(data[2].avx, data[3].avx);
389 let a3 = unpack_hi_m256(data[2].avx, data[3].avx);
390 let a4 = unpack_lo_m256(data[4].avx, data[5].avx);
391 let a5 = unpack_hi_m256(data[4].avx, data[5].avx);
392 let a6 = unpack_lo_m256(data[6].avx, data[7].avx);
393 let a7 = unpack_hi_m256(data[6].avx, data[7].avx);
394
395 pub const fn mm_shuffle(z: i32, y: i32, x: i32, w: i32) -> i32 {
396 (z << 6) | (y << 4) | (x << 2) | w
397 }
398
399 const SHUFF_LO : i32 = mm_shuffle(1,0,1,0);
400 const SHUFF_HI : i32 = mm_shuffle(3,2,3,2);
401
402 let b0 = shuffle_m256::<SHUFF_LO>(a0,a2);
405 let b1 = shuffle_m256::<SHUFF_HI>(a0,a2);
406 let b2 = shuffle_m256::<SHUFF_LO>(a1,a3);
407 let b3 = shuffle_m256::<SHUFF_HI>(a1,a3);
408 let b4 = shuffle_m256::<SHUFF_LO>(a4,a6);
409 let b5 = shuffle_m256::<SHUFF_HI>(a4,a6);
410 let b6 = shuffle_m256::<SHUFF_LO>(a5,a7);
411 let b7 = shuffle_m256::<SHUFF_HI>(a5,a7);
412
413 [
414 f32x8 { avx: permute2z_m256::<0x20>(b0, b4) },
415 f32x8 { avx: permute2z_m256::<0x20>(b1, b5) },
416 f32x8 { avx: permute2z_m256::<0x20>(b2, b6) },
417 f32x8 { avx: permute2z_m256::<0x20>(b3, b7) },
418 f32x8 { avx: permute2z_m256::<0x31>(b0, b4) },
419 f32x8 { avx: permute2z_m256::<0x31>(b1, b5) },
420 f32x8 { avx: permute2z_m256::<0x31>(b2, b6) },
421 f32x8 { avx: permute2z_m256::<0x31>(b3, b7) }
422 ]
423 } else {
424 #[inline(always)]
427 fn transpose_column(data: &[f32x8; 8], index: usize) -> f32x8 {
428 f32x8::new([
429 data[0].as_array()[index],
430 data[1].as_array()[index],
431 data[2].as_array()[index],
432 data[3].as_array()[index],
433 data[4].as_array()[index],
434 data[5].as_array()[index],
435 data[6].as_array()[index],
436 data[7].as_array()[index],
437 ])
438 }
439
440 [
441 transpose_column(&data, 0),
442 transpose_column(&data, 1),
443 transpose_column(&data, 2),
444 transpose_column(&data, 3),
445 transpose_column(&data, 4),
446 transpose_column(&data, 5),
447 transpose_column(&data, 6),
448 transpose_column(&data, 7),
449 ]
450 }
451 }
452 }
453
454 #[inline]
455 pub fn is_nan(self) -> Self {
456 pick! {
457 if #[cfg(target_feature="avx")] {
458 Self { avx: cmp_op_mask_m256::<{cmp_op!(Unordered)}>(self.avx, self.avx) }
459 } else {
460 Self {
461 a : self.a.is_nan(),
462 b : self.b.is_nan(),
463 }
464 }
465 }
466 }
467
468 #[inline]
469 pub fn is_inf(self) -> Self {
470 let shifted_inf = u32x8::from(0xFF000000);
471 let u: u32x8 = cast(self);
472 let shift_u = u << 1_u64;
473 let out = (shift_u).simd_eq(shifted_inf);
474 cast(out)
475 }
476
477 #[inline]
478 pub fn is_finite(self) -> Self {
479 let shifted_exp_mask = u32x8::from(0xFF000000);
480 let u: u32x8 = cast(self);
481 let shift_u = u << 1_u64;
482 let out = !(shift_u & shifted_exp_mask).simd_eq(shifted_exp_mask);
483 cast(out)
484 }
485
486 #[inline]
487 pub fn is_sign_positive(self) -> Self {
488 const SIGN_MASK: u32x8 = u32x8::splat((-0.0_f32).to_bits());
489
490 let bits = cast::<f32x8, u32x8>(self);
491 let sign = bits & SIGN_MASK;
492 let result = sign.simd_eq(u32x8::ZERO);
493 cast::<u32x8, f32x8>(result)
494 }
495
496 #[inline]
497 pub fn is_sign_negative(self) -> Self {
498 const SIGN_MASK: u32x8 = u32x8::splat((-0.0_f32).to_bits());
499
500 let bits = cast::<f32x8, u32x8>(self);
501 let sign = bits & SIGN_MASK;
502 let result = sign.simd_eq(SIGN_MASK);
503 cast::<u32x8, f32x8>(result)
504 }
505
506 #[inline]
507 pub fn recip(self) -> Self {
508 pick! {
509 if #[cfg(target_feature="avx")] {
510 Self { avx: reciprocal_m256(self.avx) }
511 } else {
512 Self {
513 a : self.a.recip(),
514 b : self.b.recip(),
515 }
516 }
517 }
518 }
519
520 #[inline]
521 pub fn recip_sqrt(self) -> Self {
522 pick! {
523 if #[cfg(target_feature="avx")] {
524 Self { avx: reciprocal_sqrt_m256(self.avx) }
525 } else {
526 Self {
527 a : self.a.recip_sqrt(),
528 b : self.b.recip_sqrt(),
529 }
530 }
531 }
532 }
533
534 #[inline]
535 pub fn max(self, rhs: Self) -> Self {
536 pick! {
537 if #[cfg(target_feature="avx")] {
538 rhs.is_nan().select(self, Self { avx: max_m256(self.avx, rhs.avx) })
542 } else {
543 Self {
544 a : self.a.max(rhs.a),
545 b : self.b.max(rhs.b),
546 }
547 }
548
549 }
550 }
551
552 #[inline]
553 pub fn fast_max(self, rhs: Self) -> Self {
554 pick! {
555 if #[cfg(target_feature="avx")] {
556 Self { avx: max_m256(self.avx, rhs.avx) }
557 } else {
558 Self {
559 a : self.a.fast_max(rhs.a),
560 b : self.b.fast_max(rhs.b),
561 }
562 }
563 }
564 }
565
566 #[inline]
567 pub fn min(self, rhs: Self) -> Self {
568 pick! {
569 if #[cfg(target_feature="avx")] {
570 rhs.is_nan().select(self, Self { avx: min_m256(self.avx, rhs.avx) })
574 } else {
575 Self {
576 a : self.a.min(rhs.a),
577 b : self.b.min(rhs.b),
578 }
579 }
580 }
581 }
582
583 #[inline]
584 pub fn fast_min(self, rhs: Self) -> Self {
585 pick! {
586 if #[cfg(target_feature="avx")] {
587 Self { avx: min_m256(self.avx, rhs.avx) }
588 } else {
589 Self {
590 a : self.a.fast_min(rhs.a),
591 b : self.b.fast_min(rhs.b),
592 }
593 }
594 }
595 }
596
597 #[inline]
598 pub fn clamp(self, min: Self, max: Self) -> Self {
599 pick! {
600 if #[cfg(target_feature="avx")] {
601 self.fast_clamp(min, max) | min.is_nan() | max.is_nan()
603 } else {
604 Self {
606 a: self.a.clamp(min.a, max.a),
607 b: self.b.clamp(min.b, max.b),
608 }
609 }
610 }
611 }
612
613 #[inline]
614 pub fn fast_clamp(self, min: Self, max: Self) -> Self {
615 pick! {
616 if #[cfg(target_feature="avx")] {
617 Self { avx: max_m256(min.avx, min_m256(max.avx, self.avx)) }
620 } else {
621 Self {
622 a: self.a.fast_clamp(min.a, max.a),
623 b: self.b.fast_clamp(min.b, max.b),
624 }
625 }
626 }
627 }
628
629 #[inline]
630 pub fn abs(self) -> Self {
631 pick! {
632 if #[cfg(target_feature="avx")] {
633 let non_sign_bits = f32x8::from(f32::from_bits(i32::MAX as u32));
634 self & non_sign_bits
635 } else {
636 Self {
637 a : self.a.abs(),
638 b : self.b.abs(),
639 }
640 }
641 }
642 }
643
644 #[inline]
645 pub fn floor(self) -> Self {
646 pick! {
647 if #[cfg(target_feature="avx")] {
648 Self { avx: floor_m256(self.avx) }
649 } else {
650 Self {
651 a : self.a.floor(),
652 b : self.b.floor(),
653 }
654 }
655 }
656 }
657
658 #[inline]
659 pub fn ceil(self) -> Self {
660 pick! {
661 if #[cfg(target_feature="avx")] {
662 Self { avx: ceil_m256(self.avx) }
663 } else {
664 Self {
665 a : self.a.ceil(),
666 b : self.b.ceil(),
667 }
668 }
669 }
670 }
671
672 #[inline]
673 pub fn round(self) -> Self {
674 pick! {
675 if #[cfg(target_feature="avx2")] {
676 const_f32_as_f32x8!(HALF_NEXT_DOWN, 0.5_f32.next_down());
677 const_f32_as_f32x8!(BOUNDS_LIMIT, 8388608.0);
678
679 let self_abs = self.abs();
680
681 let adjusted_self = self_abs + Self::HALF;
682 let result_abs = Self { avx: round_m256::<{round_op!(Zero)}>(adjusted_self.avx) };
683 let result_abs = result_abs & self_abs.simd_ne(HALF_NEXT_DOWN);
686
687 let bounds_mask: Self = cast(cmp_gt_mask_i32_m256i(cast(BOUNDS_LIMIT), cast(self_abs)));
689
690 bounds_mask.abs().bitselect(result_abs, self)
692 } else {
693 let [a, b] = cast::<f32x8, [f32x4; 2]>(self);
694 cast([a.round(), b.round()])
695 }
696 }
697 }
698
699 #[inline]
700 pub fn round_int(self) -> i32x8 {
701 pick! {
702 if #[cfg(target_feature="avx")] {
703 let non_nan_mask = self.simd_eq(self);
705 let non_nan = self & non_nan_mask;
706 let flip_to_max: i32x8 = cast(self.simd_ge(Self::splat(2147483648.0)));
707 let cast: i32x8 = cast(convert_to_i32_m256i_from_m256(non_nan.avx));
708 flip_to_max ^ cast
709 } else {
710 cast([
711 self.a.round_int(),
712 self.b.round_int(),
713 ])
714 }
715 }
716 }
717
718 #[inline]
719 pub fn fast_round_int(self) -> i32x8 {
720 pick! {
721 if #[cfg(target_feature="avx")] {
722 cast(convert_to_i32_m256i_from_m256(self.avx))
723 } else {
724 cast([
725 self.a.fast_round_int(),
726 self.b.fast_round_int()])
727 }
728 }
729 }
730
731 #[inline]
732 pub fn round_ties_even(self) -> Self {
733 pick! {
734 if #[cfg(target_feature="avx")] {
736 Self { avx: round_m256::<{round_op!(Nearest)}>(self.avx) }
737 } else {
738 Self {
739 a : self.a.round_ties_even(),
740 b : self.b.round_ties_even(),
741 }
742 }
743 }
744 }
745
746 #[inline]
747 pub fn trunc(self) -> Self {
748 pick! {
749 if #[cfg(target_feature="avx")] {
750 Self { avx: round_m256::<{round_op!(Zero)}>(self.avx) }
751 } else {
752 Self {
753 a : self.a.trunc(),
754 b : self.b.trunc(),
755 }
756 }
757 }
758 }
759
760 #[inline]
761 pub fn trunc_int(self) -> i32x8 {
762 pick! {
763 if #[cfg(target_feature="avx")] {
764 let non_nan_mask = self.simd_eq(self);
766 let non_nan = self & non_nan_mask;
767 let flip_to_max: i32x8 = cast(self.simd_ge(Self::splat(2147483648.0)));
768 let cast: i32x8 = cast(convert_truncate_to_i32_m256i_from_m256(non_nan.avx));
769 flip_to_max ^ cast
770 } else {
771 cast([
772 self.a.trunc_int(),
773 self.b.trunc_int(),
774 ])
775 }
776 }
777 }
778
779 #[inline]
780 pub fn fast_trunc_int(self) -> i32x8 {
781 pick! {
782 if #[cfg(all(target_feature="avx"))] {
783 cast(convert_truncate_to_i32_m256i_from_m256(self.avx))
784 } else {
785 cast([
786 self.a.fast_trunc_int(),
787 self.b.fast_trunc_int(),
788 ])
789 }
790 }
791 }
792
793 #[inline]
801 pub fn mul_add(self, a: Self, b: Self) -> Self {
802 pick! {
803 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
804 Self { avx: fused_mul_add_m256(self.avx, a.avx, b.avx) }
805 } else if #[cfg(target_feature="avx")] {
806 (self * a) + b
808 } else {
809 Self {
810 a : self.a.mul_add(a.a, b.a),
811 b : self.b.mul_add(a.b, b.b),
812 }
813 }
814 }
815 }
816
817 #[inline]
825 pub fn mul_sub(self, a: Self, b: Self) -> Self {
826 pick! {
827 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
828 Self { avx: fused_mul_sub_m256(self.avx, a.avx, b.avx) }
829 } else if #[cfg(target_feature="avx")] {
830 (self * a) - b
832 } else {
833 Self {
834 a : self.a.mul_sub(a.a, b.a),
835 b : self.b.mul_sub(a.b, b.b),
836 }
837 }
838 }
839 }
840
841 #[inline]
849 pub fn mul_neg_add(self, a: Self, b: Self) -> Self {
850 pick! {
851 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
852 Self { avx: fused_mul_neg_add_m256(self.avx, a.avx, b.avx) }
853 } else if #[cfg(target_feature="avx")] {
854 b - (self * a)
856 } else {
857 Self {
858 a : self.a.mul_neg_add(a.a, b.a),
859 b : self.b.mul_neg_add(a.b, b.b),
860 }
861 }
862 }
863 }
864
865 #[inline]
873 pub fn mul_neg_sub(self, a: Self, b: Self) -> Self {
874 pick! {
875 if #[cfg(all(target_feature="avx",target_feature="fma"))] {
876 Self { avx: fused_mul_neg_sub_m256(self.avx, a.avx, b.avx) }
877 } else if #[cfg(target_feature="avx")] {
878 -(self * a) - b
880 } else {
881 Self {
882 a : self.a.mul_neg_sub(a.a, b.a),
883 b : self.b.mul_neg_sub(a.b, b.b),
884 }
885 }
886 }
887 }
888
889 #[inline]
890 pub fn powf_simd(self, n: Self) -> Self {
891 const_f32_as_f32x8!(ln2f_hi, 0.693359375);
892 const_f32_as_f32x8!(ln2f_lo, -2.12194440e-4);
893 const_f32_as_f32x8!(P0logf, 3.3333331174E-1);
894 const_f32_as_f32x8!(P1logf, -2.4999993993E-1);
895 const_f32_as_f32x8!(P2logf, 2.0000714765E-1);
896 const_f32_as_f32x8!(P3logf, -1.6668057665E-1);
897 const_f32_as_f32x8!(P4logf, 1.4249322787E-1);
898 const_f32_as_f32x8!(P5logf, -1.2420140846E-1);
899 const_f32_as_f32x8!(P6logf, 1.1676998740E-1);
900 const_f32_as_f32x8!(P7logf, -1.1514610310E-1);
901 const_f32_as_f32x8!(P8logf, 7.0376836292E-2);
902
903 const_f32_as_f32x8!(p2expf, 1.0 / 2.0); const_f32_as_f32x8!(p3expf, 1.0 / 6.0);
905 const_f32_as_f32x8!(p4expf, 1.0 / 24.0);
906 const_f32_as_f32x8!(p5expf, 1.0 / 120.0);
907 const_f32_as_f32x8!(p6expf, 1.0 / 720.0);
908 const_f32_as_f32x8!(p7expf, 1.0 / 5040.0);
909
910 let x1 = self.abs();
911 let x = x1.fraction_2();
912 let mask = x.simd_gt(f32x8::SQRT_2 * f32x8::HALF);
913 let x = (!mask).select(x + x, x);
914
915 let x = x - f32x8::ONE;
916 let x2 = x * x;
917 let lg1 = polynomial_8!(
918 x, P0logf, P1logf, P2logf, P3logf, P4logf, P5logf, P6logf, P7logf, P8logf
919 );
920 let lg1 = lg1 * x2 * x;
921
922 let ef = x1.exponent();
923 let ef = mask.select(ef + f32x8::ONE, ef);
924 let e1 = (ef * n).round_ties_even();
925 let yr = ef.mul_sub(n, e1);
926
927 let lg = f32x8::HALF.mul_neg_add(x2, x) + lg1;
928 let x2_err = (f32x8::HALF * x).mul_sub(x, f32x8::HALF * x2);
929 let lg_err = f32x8::HALF.mul_add(x2, lg - x) - lg1;
930
931 let e2 = (lg * n * f32x8::LOG2_E).round_ties_even();
932 let v = lg.mul_sub(n, e2 * ln2f_hi);
933 let v = e2.mul_neg_add(ln2f_lo, v);
934 let v = v - (lg_err + x2_err).mul_sub(n, yr * f32x8::LN_2);
935
936 let x = v;
937 let e3 = (x * f32x8::LOG2_E).round_ties_even();
938 let x = e3.mul_neg_add(f32x8::LN_2, x);
939 let x2 = x * x;
940 let z = x2.mul_add(
941 polynomial_5!(x, p2expf, p3expf, p4expf, p5expf, p6expf, p7expf),
942 x + f32x8::ONE,
943 );
944
945 let ee = e1 + e2 + e3;
946 let ei = cast::<_, i32x8>(ee.round_int());
947 let ej = cast::<_, i32x8>(ei + (cast::<_, i32x8>(z) >> 23));
948
949 let overflow = cast::<_, f32x8>(ej.simd_gt(i32x8::splat(0x0FF)))
950 | (ee.simd_gt(f32x8::splat(300.0)));
951 let underflow = cast::<_, f32x8>(ej.simd_lt(i32x8::splat(0x000)))
952 | (ee.simd_lt(f32x8::splat(-300.0)));
953
954 let z = cast::<_, f32x8>(cast::<_, i32x8>(z) + (ei << 23));
956 let z = underflow.select(f32x8::ZERO, z);
958 let z = overflow.select(Self::infinity(), z);
959
960 let x_zero = self.is_zero_or_subnormal();
962 let z = x_zero.select(
963 n.simd_lt(f32x8::ZERO).select(
964 Self::infinity(),
965 n.simd_eq(f32x8::ZERO).select(f32x8::ONE, f32x8::ZERO),
966 ),
967 z,
968 );
969
970 let x_sign = self.is_sign_negative();
971 let z = if x_sign.any() {
972 let yi = n.simd_eq(n.round_ties_even());
974
975 let y_odd = cast::<i32x8, f32x8>(n.round_int() << 31);
977
978 let z1 = yi
979 .select(z | y_odd, self.simd_eq(Self::ZERO).select(z, Self::nan_pow()));
980
981 x_sign.select(z1, z)
982 } else {
983 z
984 };
985
986 let x_finite = self.is_finite();
987 let y_finite = n.is_finite();
988 let e_finite = ee.is_finite();
989 if (x_finite & y_finite & (e_finite | x_zero)).all() {
990 return z;
991 }
992
993 (self.is_nan() | n.is_nan()).select(self + n, z)
994 }
995
996 #[inline]
997 pub fn sqrt(self) -> Self {
998 pick! {
999 if #[cfg(target_feature="avx")] {
1000 Self { avx: sqrt_m256(self.avx) }
1001 } else {
1002 Self {
1003 a : self.a.sqrt(),
1004 b : self.b.sqrt(),
1005 }
1006 }
1007 }
1008 }
1009
1010 #[inline]
1012 pub fn exp(self) -> Self {
1013 const_f32_as_f32x8!(P0, 1.0 / 2.0);
1014 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1015 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1016 const_f32_as_f32x8!(P3, 1.0 / 120.0);
1017 const_f32_as_f32x8!(P4, 1.0 / 720.0);
1018 const_f32_as_f32x8!(P5, 1.0 / 5040.0);
1019 const_f32_as_f32x8!(LN2D_HI, 0.693359375);
1026 const_f32_as_f32x8!(LN2D_LO, -2.12194440e-4);
1027 let max_x = f32x8::from(88.723);
1030 let min_x = f32x8::from(-103.63);
1031 let finite = self.is_finite();
1033 let neg_underflow = self.simd_lt(min_x) & finite;
1034 if neg_underflow.all() {
1035 return Self::ZERO;
1036 }
1037 let max_r = f32x8::from(127.0);
1038 let r = (self * Self::LOG2_E).round_ties_even();
1039 let big = r.simd_gt(max_r);
1040 let r_safe = big.select(max_r, r);
1041 let excess = r - max_r;
1042 let excess = big.select(excess, Self::ZERO);
1043 let scale = Self::vm_pow2n(excess);
1044 let x = r.mul_neg_add(LN2D_HI, self);
1045 let x = r.mul_neg_add(LN2D_LO, x);
1046 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1047 let x2 = x * x;
1048 let z = z.mul_add(x2, x);
1049 let n2 = Self::vm_pow2n(r_safe);
1050 let z = (z + Self::ONE) * scale * n2;
1051 let nan_mask = self.is_nan();
1052 let mut result = nan_mask.select(Self::nan_pow(), z);
1053 let pos_overflow = self.simd_gt(max_x) & finite;
1054 result = pos_overflow.select(Self::infinity(), result);
1055 result = neg_underflow.select(Self::ZERO, result);
1056 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1057 result = pos_inf.select(Self::infinity(), result);
1058 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1059 result = neg_inf.select(Self::ZERO, result);
1060 result
1061 }
1062
1063 #[inline]
1064 pub fn exp2(self) -> Self {
1065 const_f32_as_f32x8!(P2, 1.0 / 2.0);
1066 const_f32_as_f32x8!(P3, 1.0 / 6.0);
1067 const_f32_as_f32x8!(P4, 1.0 / 24.0);
1068 const_f32_as_f32x8!(P5, 1.0 / 120.0);
1069 const_f32_as_f32x8!(P6, 1.0 / 720.0);
1070 const_f32_as_f32x8!(P7, 1.0 / 5040.0);
1071
1072 let max_x = f32x8::from(127.99999);
1075 let min_x = f32x8::from(-149.5);
1076 let finite = self.is_finite();
1077 let neg_underflow = self.simd_lt(min_x) & finite;
1078 if neg_underflow.all() {
1079 return Self::ZERO;
1080 }
1081
1082 let round = self.round_ties_even();
1083 let max_r = f32x8::from(127.0);
1084 let big = round.simd_gt(max_r);
1085 let r_safe = big.select(max_r, round);
1086 let excess = round - max_r;
1087 let excess = big.select(excess, Self::ZERO);
1088 let scale = Self::vm_pow2n(excess);
1089
1090 let fract = (self - round) * Self::LN_2;
1091 let fract_partial_exp2 = polynomial_5!(fract, P2, P3, P4, P5, P6, P7);
1092 let fract2 = fract * fract;
1093 let fract_exp2 = fract_partial_exp2.mul_add(fract2, fract) + Self::ONE;
1094
1095 let n2 = Self::vm_pow2n(r_safe);
1096 let result = fract_exp2 * scale * n2;
1097
1098 let nan_mask = self.is_nan();
1099 let mut result = nan_mask.select(Self::nan_pow(), result);
1100 let pos_overflow = self.simd_gt(max_x) & finite;
1101 result = pos_overflow.select(Self::infinity(), result);
1102 result = neg_underflow.select(Self::ZERO, result);
1103 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1104 result = pos_inf.select(Self::infinity(), result);
1105 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1106 result = neg_inf.select(Self::ZERO, result);
1107 result
1108 }
1109
1110 #[inline]
1111 pub fn ln(self) -> Self {
1112 const_f32_as_f32x8!(HALF, 0.5);
1113 const_f32_as_f32x8!(P0, 3.3333331174E-1);
1114 const_f32_as_f32x8!(P1, -2.4999993993E-1);
1115 const_f32_as_f32x8!(P2, 2.0000714765E-1);
1116 const_f32_as_f32x8!(P3, -1.6668057665E-1);
1117 const_f32_as_f32x8!(P4, 1.4249322787E-1);
1118 const_f32_as_f32x8!(P5, -1.2420140846E-1);
1119 const_f32_as_f32x8!(P6, 1.1676998740E-1);
1120 const_f32_as_f32x8!(P7, -1.1514610310E-1);
1121 const_f32_as_f32x8!(P8, 7.0376836292E-2);
1122 const_f32_as_f32x8!(LN2F_HI, 0.693359375);
1123 const_f32_as_f32x8!(LN2F_LO, -2.12194440e-4);
1124 const_f32_as_f32x8!(VM_SMALLEST_NORMAL, 1.17549435E-38);
1125
1126 let x1 = self;
1127 let x = Self::fraction_2(x1);
1128 let e = Self::exponent(x1);
1129 let mask = x.simd_gt(Self::SQRT_2 * HALF);
1130 let x = (!mask).select(x + x, x);
1131 let fe = mask.select(e + Self::ONE, e);
1132 let x = x - Self::ONE;
1133 let res = polynomial_8!(x, P0, P1, P2, P3, P4, P5, P6, P7, P8);
1134 let x2 = x * x;
1135 let res = x2 * x * res;
1136 let res = fe.mul_add(LN2F_LO, res);
1137 let res = res + x2.mul_neg_add(HALF, x);
1138 let res = fe.mul_add(LN2F_HI, res);
1139 let overflow = !self.is_finite();
1140 let underflow = x1.simd_lt(VM_SMALLEST_NORMAL);
1141 let mask = overflow | underflow;
1142 if !mask.any() {
1143 res
1144 } else {
1145 let is_zero = self.is_zero_or_subnormal();
1146 let res = underflow.select(Self::nan_log(), res);
1147 let res = is_zero.select(-Self::infinity(), res);
1152 let res = overflow.select(self, res);
1153 let res = (!self.is_finite() & self.is_sign_negative())
1155 .select(Self::nan_log(), res);
1156 res
1157 }
1158 }
1159
1160 #[inline]
1161 pub fn cbrt(self) -> Self {
1162 let a = self.abs();
1163 let zero = a.simd_eq(Self::ZERO);
1164 if zero.all() {
1165 return self; }
1167 let inf = a.is_inf();
1168 let nan = self.is_nan();
1169
1170 let tiny = a.simd_lt(Self::from(f32::MIN_POSITIVE));
1171 let a_work = tiny.select(a * Self::from(16777216.0), a);
1172
1173 let e = Self::exponent(a_work) + Self::ONE;
1174 let d = Self::fraction_2(a_work);
1175
1176 const_f32_as_f32x8!(C0, 2.2241257);
1183 const_f32_as_f32x8!(C1, -3.8095417);
1184 const_f32_as_f32x8!(C2, 5.8982625);
1185 const_f32_as_f32x8!(C3, -5.532182);
1186 const_f32_as_f32x8!(C4, 2.8208892);
1187 const_f32_as_f32x8!(C5, -0.60156447);
1188 let mut x = polynomial_5!(d, C0, C1, C2, C3, C4, C5);
1189
1190 let x2 = x * x;
1191 let x4 = x2 * x2;
1192 x = x - d.mul_add(x4, -x) * Self::from(1.0 / 3.0);
1193 let mut y = (d * x) * x;
1195 let yx = y * x;
1196 let t = Self::from(2.0 / 3.0);
1197 y = y - t * y * (yx - Self::ONE);
1198
1199 let three = Self::from(3.0);
1201 let two = Self::from(2.0);
1202 let neg = e.simd_lt(Self::ZERO);
1203 let e_adj = neg.select(e - two, e);
1204 let k = (e_adj / three).trunc();
1205 let r = e - three * k;
1206 const_f32_as_f32x8!(CBRT2, 1.259921);
1207 const_f32_as_f32x8!(CBRT4, 1.587401);
1208 y = r.simd_eq(Self::ONE).select(y * CBRT2, y);
1209 y = r.simd_eq(two).select(y * CBRT4, y);
1210 y *= Self::vm_pow2n(k);
1211 y = tiny.select(y / Self::from(256.0_f32), y);
1212
1213 let result = y.flip_signs(self);
1214 let result = nan.select(self, result);
1215 let result = zero.select(self, result);
1216 let result = inf.select(self, result);
1217 result
1218 }
1219
1220 #[inline]
1221 pub fn asin(self) -> Self {
1222 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
1225 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
1226 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
1227 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
1228 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
1229
1230 let xa = self.abs();
1231 let big = xa.simd_ge(f32x8::splat(0.5));
1232
1233 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
1234 let x2 = xa * xa;
1235 let x3 = big.select(x1, x2);
1236
1237 let xb = x1.sqrt();
1238
1239 let x4 = big.select(xb, xa);
1240
1241 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1242 let z = z.mul_add(x3 * x4, x4);
1243
1244 let z1 = z + z;
1245
1246 let z3 = f32x8::FRAC_PI_2 - z1;
1248 let asin = big.select(z3, z);
1249 let asin = asin.flip_signs(self);
1250
1251 asin
1252 }
1253
1254 #[inline]
1255 pub fn acos(self) -> Self {
1256 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
1259 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
1260 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
1261 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
1262 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
1263
1264 let xa = self.abs();
1265 let big = xa.simd_ge(f32x8::splat(0.5));
1266
1267 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
1268 let x2 = xa * xa;
1269 let x3 = big.select(x1, x2);
1270
1271 let xb = x1.sqrt();
1272
1273 let x4 = big.select(xb, xa);
1274
1275 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1276 let z = z.mul_add(x3 * x4, x4);
1277
1278 let z1 = z + z;
1279
1280 let z3 = self.simd_lt(f32x8::ZERO).select(f32x8::PI - z1, z1);
1282 let z4 = f32x8::FRAC_PI_2 - z.flip_signs(self);
1283 let acos = big.select(z3, z4);
1284
1285 acos
1286 }
1287
1288 #[inline]
1289 pub fn atan(self) -> Self {
1290 const_f32_as_f32x8!(P3atanf, 8.05374449538E-2);
1293 const_f32_as_f32x8!(P2atanf, -1.38776856032E-1);
1294 const_f32_as_f32x8!(P1atanf, 1.99777106478E-1);
1295 const_f32_as_f32x8!(P0atanf, -3.33329491539E-1);
1296
1297 let t = self.abs();
1298
1299 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1303 let notbig = t.simd_le(Self::SQRT_2 + Self::ONE);
1304
1305 let mut s = notbig.select(Self::FRAC_PI_4, Self::FRAC_PI_2);
1306 s = notsmal & s;
1307
1308 let mut a = notbig & t;
1309 a = notsmal.select(a - Self::ONE, a);
1310 let mut b = notbig & Self::ONE;
1311 b = notsmal.select(b + t, b);
1312 let z = a / b;
1313
1314 let zz = z * z;
1315
1316 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1318 re = re.mul_add(zz * z, z) + s;
1319
1320 re = (self.is_sign_negative()).select(-re, re);
1322
1323 re
1324 }
1325
1326 #[inline]
1327 pub fn atan2(self, x: Self) -> Self {
1328 const_f32_as_f32x8!(P3atanf, 8.05374449538E-2);
1331 const_f32_as_f32x8!(P2atanf, -1.38776856032E-1);
1332 const_f32_as_f32x8!(P1atanf, 1.99777106478E-1);
1333 const_f32_as_f32x8!(P0atanf, -3.33329491539E-1);
1334
1335 let y = self;
1336
1337 let x1 = x.abs();
1339 let y1 = y.abs();
1340 let swapxy = y1.simd_gt(x1);
1341 let mut x2 = swapxy.select(y1, x1);
1343 let mut y2 = swapxy.select(x1, y1);
1344
1345 let both_infinite = x.is_inf() & y.is_inf();
1347 if both_infinite.any() {
1348 let minus_one = -Self::ONE;
1349 x2 = both_infinite.select(x2 & minus_one, x2);
1350 y2 = both_infinite.select(y2 & minus_one, y2);
1351 }
1352
1353 let t = y2 / x2;
1355
1356 let notsmal = t.simd_ge(Self::SQRT_2 - Self::ONE);
1359
1360 let a = notsmal.select(t - Self::ONE, t);
1361 let b = notsmal.select(t + Self::ONE, Self::ONE);
1362 let s = notsmal & Self::FRAC_PI_4;
1363 let z = a / b;
1364
1365 let zz = z * z;
1366
1367 let mut re = polynomial_3!(zz, P0atanf, P1atanf, P2atanf, P3atanf);
1369 re = re.mul_add(zz * z, z) + s;
1370
1371 re = swapxy.select(Self::FRAC_PI_2 - re, re);
1373 re = ((x | y).simd_eq(Self::ZERO)).select(Self::ZERO, re);
1374 re = (x.is_sign_negative()).select(Self::PI - re, re);
1375
1376 re = (y.is_sign_negative()).select(-re, re);
1378
1379 re
1380 }
1381
1382 #[inline]
1383 pub fn sin_cos(self) -> (Self, Self) {
1384 const_f32_as_f32x8!(DP1F, 0.78515625_f32 * 2.0);
1388 const_f32_as_f32x8!(DP2F, 2.4187564849853515625E-4_f32 * 2.0);
1389 const_f32_as_f32x8!(DP3F, 3.77489497744594108E-8_f32 * 2.0);
1390
1391 const_f32_as_f32x8!(P0sinf, -1.6666654611E-1);
1392 const_f32_as_f32x8!(P1sinf, 8.3321608736E-3);
1393 const_f32_as_f32x8!(P2sinf, -1.9515295891E-4);
1394
1395 const_f32_as_f32x8!(P0cosf, 4.166664568298827E-2);
1396 const_f32_as_f32x8!(P1cosf, -1.388731625493765E-3);
1397 const_f32_as_f32x8!(P2cosf, 2.443315711809948E-5);
1398
1399 const_f32_as_f32x8!(TWO_OVER_PI, 2.0 / core::f32::consts::PI);
1400
1401 let xa = self.abs();
1402
1403 let y = (xa * TWO_OVER_PI).round_ties_even();
1405 let q: i32x8 = y.round_int();
1406
1407 let x = y.mul_neg_add(DP3F, y.mul_neg_add(DP2F, y.mul_neg_add(DP1F, xa)));
1408
1409 let x2 = x * x;
1410 let mut s = polynomial_2!(x2, P0sinf, P1sinf, P2sinf) * (x * x2) + x;
1411 let mut c = polynomial_2!(x2, P0cosf, P1cosf, P2cosf) * (x2 * x2)
1412 + f32x8::from(0.5).mul_neg_add(x2, f32x8::from(1.0));
1413
1414 let swap = !(q & i32x8::from(1)).simd_eq(i32x8::from(0));
1415
1416 let mut overflow: f32x8 = cast(q.simd_gt(i32x8::from(0x2000000)));
1417 overflow &= xa.is_finite();
1418 s = overflow.select(f32x8::from(0.0), s);
1419 c = overflow.select(f32x8::from(1.0), c);
1420
1421 let mut sin1 = cast::<_, f32x8>(swap).select(c, s);
1423 let sign_sin: i32x8 = (q << 30) ^ cast::<_, i32x8>(self);
1424 sin1 = sin1.flip_signs(cast(sign_sin));
1425
1426 let mut cos1 = cast::<_, f32x8>(swap).select(s, c);
1428 let sign_cos: i32x8 = ((q + i32x8::from(1)) & i32x8::from(2)) << 30;
1429 cos1 ^= cast::<_, f32x8>(sign_cos);
1430
1431 let finite = self.is_finite();
1433 let nan = Self::splat(f32::NAN);
1434 let sin_final = finite.select(sin1, nan);
1435 let cos_final = finite.select(cos1, nan);
1436
1437 (sin_final, cos_final)
1438 }
1439
1440 #[inline]
1441 pub fn asin_acos(self) -> (Self, Self) {
1442 const_f32_as_f32x8!(P4asinf, 4.2163199048E-2);
1445 const_f32_as_f32x8!(P3asinf, 2.4181311049E-2);
1446 const_f32_as_f32x8!(P2asinf, 4.5470025998E-2);
1447 const_f32_as_f32x8!(P1asinf, 7.4953002686E-2);
1448 const_f32_as_f32x8!(P0asinf, 1.6666752422E-1);
1449
1450 let xa = self.abs();
1451 let big = xa.simd_ge(f32x8::splat(0.5));
1452
1453 let x1 = f32x8::splat(0.5) * (f32x8::ONE - xa);
1454 let x2 = xa * xa;
1455 let x3 = big.select(x1, x2);
1456
1457 let xb = x1.sqrt();
1458
1459 let x4 = big.select(xb, xa);
1460
1461 let z = polynomial_4!(x3, P0asinf, P1asinf, P2asinf, P3asinf, P4asinf);
1462 let z = z.mul_add(x3 * x4, x4);
1463
1464 let z1 = z + z;
1465
1466 let z3 = self.simd_lt(f32x8::ZERO).select(f32x8::PI - z1, z1);
1468 let z4 = f32x8::FRAC_PI_2 - z.flip_signs(self);
1469 let acos = big.select(z3, z4);
1470
1471 let z3 = f32x8::FRAC_PI_2 - z1;
1473 let asin = big.select(z3, z);
1474 let asin = asin.flip_signs(self);
1475
1476 (asin, acos)
1477 }
1478
1479 #[inline]
1480 pub fn exp_m1(self) -> Self {
1481 if self.simd_lt(f32x8::from(-17.329)).all() {
1485 return f32x8::from(-1.0);
1486 }
1487 const_f32_as_f32x8!(P0, 1.0 / 2.0);
1488 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1489 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1490 const_f32_as_f32x8!(P3, 1.0 / 120.0);
1491 const_f32_as_f32x8!(P4, 1.0 / 720.0);
1492 const_f32_as_f32x8!(P5, 1.0 / 5040.0);
1493 const_f32_as_f32x8!(LN2D_HI, 0.693359375);
1500 const_f32_as_f32x8!(LN2D_LO, -2.12194440e-4);
1501 let max_x = f32x8::from(88.723);
1504 let min_x = f32x8::from(-103.63);
1505 let max_r = f32x8::from(127.0);
1506 let r = (self * Self::LOG2_E).round_ties_even();
1507 let big = r.simd_gt(max_r);
1508 let r_safe = big.select(max_r, r);
1509 let excess = r - max_r;
1510 let excess = big.select(excess, Self::ZERO);
1511 let scale = Self::vm_pow2n(excess);
1512 let x = r.mul_neg_add(LN2D_HI, self);
1513 let x = r.mul_neg_add(LN2D_LO, x);
1514 let z = polynomial_5!(x, P0, P1, P2, P3, P4, P5);
1515 let x2 = x * x;
1516 let z = z.mul_add(x2, x);
1517 let n2 = Self::vm_pow2n(r_safe);
1518 let exp_val = (z + Self::ONE) * scale * n2;
1519 let r_is_zero = r.simd_eq(Self::ZERO);
1520 let z = r_is_zero.select(z, exp_val - Self::ONE);
1521 let nan_mask = self.is_nan();
1522 let finite = self.is_finite();
1523 let mut result = nan_mask.select(Self::nan_pow(), z);
1524 let pos_overflow = self.simd_gt(max_x) & finite;
1525 result = pos_overflow.select(Self::infinity(), result);
1526 let neg_underflow = self.simd_lt(min_x) & finite;
1527 result = neg_underflow.select(-Self::ONE, result);
1528 let pos_inf = !finite & !self.is_sign_negative() & !nan_mask;
1529 result = pos_inf.select(Self::infinity(), result);
1530 let neg_inf = !finite & self.is_sign_negative() & !nan_mask;
1531 result = neg_inf.select(-Self::ONE, result);
1532 let is_zero = self.simd_eq(Self::ZERO);
1533 result = is_zero.select(self, result);
1534 result
1535 }
1536
1537 #[inline]
1538 pub fn ln_1p(self) -> Self {
1539 let u = self + Self::ONE;
1547 let eq = u.simd_eq(Self::ONE);
1548 let ln_u = Self::ln(u);
1549 let correction = self * (ln_u / (u - Self::ONE));
1550 let result = eq.select(self, correction);
1551 let over = u.is_inf();
1552 over.select(ln_u, result)
1553 }
1554
1555 #[inline]
1556 pub fn sinh(self) -> Self {
1557 const_f32_as_f32x8!(P0, 1.0);
1558 const_f32_as_f32x8!(P1, 1.0 / 6.0);
1559 const_f32_as_f32x8!(P2, 1.0 / 120.0);
1560 const_f32_as_f32x8!(P3, 1.0 / 5040.0);
1561 let a = self.abs();
1562 let small = a.simd_lt(f32x8::from(0.5));
1564 let t = a * a;
1565 let poly = a * polynomial_3!(t, P0, P1, P2, P3);
1566 let exp_based = {
1567 let e = a.exp();
1568 (e - Self::ONE / e) * Self::HALF
1569 };
1570 let result = small.select(poly, exp_based);
1571 result.flip_signs(self)
1572 }
1573
1574 #[inline]
1575 pub fn cosh(self) -> Self {
1576 const_f32_as_f32x8!(P0, 1.0);
1577 const_f32_as_f32x8!(P1, 1.0 / 2.0);
1578 const_f32_as_f32x8!(P2, 1.0 / 24.0);
1579 const_f32_as_f32x8!(P3, 1.0 / 720.0);
1580 let a = self.abs();
1581 let small = a.simd_lt(f32x8::from(0.5));
1583 let t = a * a;
1584 let poly = polynomial_3!(t, P0, P1, P2, P3);
1585 let exp_based = {
1586 let e = a.exp();
1587 (e + Self::ONE / e) * Self::HALF
1588 };
1589 small.select(poly, exp_based)
1590 }
1591
1592 #[inline]
1593 pub fn tanh(self) -> Self {
1594 let a = self.abs();
1598 let large = a.simd_gt(f32x8::from(9.011));
1599 if large.all() {
1600 return Self::ONE.flip_signs(self);
1601 }
1602 let small = a.simd_lt(f32x8::from(2e-4));
1603 let exp_based = {
1604 let t = (Self::from(-2.0) * a).exp_m1();
1605 let pos = -t / (t + Self::from(2.0));
1606 pos.flip_signs(self)
1607 };
1608 let result = small.select(self, exp_based);
1609 large.select(Self::ONE.flip_signs(self), result)
1610 }
1611}
1612
1613impl f32x8 {
1616 #[inline]
1617 fn vm_pow2n(self) -> Self {
1618 const_f32_as_f32x8!(pow2_23, 8388608.0);
1619 const_f32_as_f32x8!(bias, 127.0);
1620 let a = self + (bias + pow2_23);
1621 let c = cast::<_, i32x8>(a) << 23;
1622 let std_result = cast::<_, f32x8>(c);
1623
1624 let min_exp = f32x8::from(-126.0);
1625 let is_sub = self.simd_lt(min_exp);
1626 if is_sub.any() {
1627 let valid = self.simd_ge(f32x8::from(-149.0));
1628 let shift_f = self + f32x8::from(149.0);
1629 let mut shift_i = shift_f.trunc_int();
1630 shift_i = cast::<_, i32x8>(valid).select(shift_i, i32x8::ZERO);
1631 let mantissa = i32x8::ONE << shift_i;
1632 let sub_result = cast::<_, f32x8>(mantissa);
1633 let sub_result = valid.select(sub_result, f32x8::ZERO);
1634 is_sub.select(sub_result, std_result)
1635 } else {
1636 std_result
1637 }
1638 }
1639
1640 #[inline]
1641 fn exponent(self) -> f32x8 {
1642 const_f32_as_f32x8!(pow2_23, 8388608.0);
1643 const_f32_as_f32x8!(bias, 127.0);
1644 let a = cast::<_, u32x8>(self);
1645 let b = a >> 23;
1646 let c = b | cast::<_, u32x8>(pow2_23);
1647 let d = cast::<_, f32x8>(c);
1648 let e = d - (pow2_23 + bias);
1649 e
1650 }
1651
1652 #[inline]
1653 fn fraction_2(self) -> Self {
1654 let t1 = cast::<_, u32x8>(self);
1655 let t2 = cast::<_, u32x8>(
1656 (t1 & u32x8::from(0x007FFFFF)) | u32x8::from(0x3F000000),
1657 );
1658 cast::<_, f32x8>(t2)
1659 }
1660 #[inline]
1661 fn is_zero_or_subnormal(self) -> Self {
1662 let t = cast::<_, i32x8>(self);
1663 let t = t & i32x8::splat(0x7F800000);
1664 let mask = t.simd_eq(i32x8::splat(0));
1665 cast::<_, f32x8>(mask)
1666 }
1667 #[inline]
1668 fn infinity() -> Self {
1669 cast::<_, f32x8>(i32x8::splat(0x7F800000))
1670 }
1671 #[inline]
1672 fn nan_log() -> Self {
1673 cast::<_, f32x8>(i32x8::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1674 }
1675 #[inline]
1676 fn nan_pow() -> Self {
1677 cast::<_, f32x8>(i32x8::splat(0x7FC00000 | 0x101 & 0x003FFFFF))
1678 }
1679
1680 #[inline]
1682 pub fn from_i32x8(v: i32x8) -> Self {
1683 pick! {
1684 if #[cfg(target_feature="avx2")] {
1685 Self { avx: convert_to_m256_from_i32_m256i(v.avx2) }
1686 } else {
1687 Self::new([
1688 v.as_array()[0] as f32,
1689 v.as_array()[1] as f32,
1690 v.as_array()[2] as f32,
1691 v.as_array()[3] as f32,
1692 v.as_array()[4] as f32,
1693 v.as_array()[5] as f32,
1694 v.as_array()[6] as f32,
1695 v.as_array()[7] as f32,
1696 ])
1697 }
1698 }
1699 }
1700
1701 #[inline]
1711 #[must_use]
1712 #[deprecated(since = "1.4.0", note = "renamed to `is_sign_negative`")]
1713 pub fn sign_bit(self) -> Self {
1714 self.is_sign_negative()
1715 }
1716}