Skip to main content

simba/simd/
wide_simd_impl.rs

1#![allow(missing_docs)]
2#![allow(non_camel_case_types)] // For the simd type aliases.
3
4//! Traits for SIMD values.
5
6use crate::scalar::{ComplexField, Field, RealField, SubsetOf, SupersetOf};
7use crate::simd::{
8    PrimitiveSimdValue, SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, SimdSigned,
9    SimdValue,
10};
11use approx::AbsDiffEq;
12use num::{FromPrimitive, Num, One, Zero};
13use num_traits::Bounded;
14use std::{
15    cmp::PartialEq,
16    ops::{
17        Add, AddAssign, BitAnd, BitOr, BitXor, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem,
18        RemAssign, Sub, SubAssign,
19    },
20};
21
22#[cfg(feature = "rkyv")]
23macro_rules! impl_rkyv {
24    ($type:ty, $array:ty) => {
25        impl rkyv::Archive for $type {
26            type Archived = $array;
27            type Resolver = ();
28
29            #[inline]
30            unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) {
31                out.write((*self).into_arr());
32            }
33        }
34
35        impl<S: rkyv::Fallible + ?Sized> rkyv::Serialize<S> for $type {
36            #[inline]
37            fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
38                Ok(())
39            }
40        }
41
42        impl<D: rkyv::Fallible + ?Sized> rkyv::Deserialize<$type, D> for rkyv::Archived<$type> {
43            #[inline]
44            fn deserialize(&self, _: &mut D) -> Result<$type, D::Error> {
45                Ok(<$type>::from_arr(*self))
46            }
47        }
48    };
49}
50
51/// A wrapper type of `wide::f32x4` that implements all the relevant traits from `num` and `simba`.
52///
53/// This is needed to overcome the orphan rules.
54#[repr(transparent)]
55#[derive(Copy, Clone, Debug, Default)]
56pub struct WideF32x4(pub wide::f32x4);
57
58#[cfg(feature = "rkyv")]
59impl_rkyv!(WideF32x4, [f32; 4]);
60
61/// An SIMD boolean structure associated to `wide::f32x4` that implements all the relevant traits from `simba`.
62///
63/// This is needed to overcome the orphan rules.
64#[repr(transparent)]
65#[derive(Copy, Clone, Debug, Default)]
66pub struct WideBoolF32x4(pub wide::f32x4);
67
68#[cfg(feature = "rkyv")]
69impl_rkyv!(WideBoolF32x4, [f32; 4]);
70
71/// A wrapper type of `wide::f32x8` that implements all the relevant traits from `num` and `simba`.
72///
73/// This is needed to overcome the orphan rules.
74#[repr(transparent)]
75#[derive(Copy, Clone, Debug, Default)]
76pub struct WideF32x8(pub wide::f32x8);
77
78#[cfg(feature = "rkyv")]
79impl_rkyv!(WideF32x8, [f32; 8]);
80
81/// An SIMD boolean structure associated to `wide::f32x8` that implements all the relevant traits from `simba`.
82///
83/// This is needed to overcome the orphan rules.
84#[repr(transparent)]
85#[derive(Copy, Clone, Debug, Default)]
86pub struct WideBoolF32x8(pub wide::f32x8);
87
88#[cfg(feature = "rkyv")]
89impl_rkyv!(WideBoolF32x8, [f32; 8]);
90
91/// A wrapper type of `wide::f64x4` that implements all the relevant traits from `num` and `simba`.
92///
93/// This is needed to overcome the orphan rules.
94#[repr(transparent)]
95#[derive(Copy, Clone, Debug, Default)]
96pub struct WideF64x4(pub wide::f64x4);
97
98#[cfg(feature = "rkyv")]
99impl_rkyv!(WideF64x4, [f64; 4]);
100
101/// An SIMD boolean structure associated to `wide::f64x4` that implements all the relevant traits from `simba`.
102///
103/// This is needed to overcome the orphan rules.
104#[repr(transparent)]
105#[derive(Copy, Clone, Debug, Default)]
106pub struct WideBoolF64x4(pub wide::f64x4);
107
108#[cfg(feature = "rkyv")]
109impl_rkyv!(WideBoolF64x4, [f64; 4]);
110
111macro_rules! impl_wide_f32 (
112    ($f32: ident, $f32xX: ident, $WideF32xX: ident, $WideBoolF32xX: ident, $lanes: expr; $($ii: expr),+) => {
113        impl PrimitiveSimdValue for $WideF32xX {}
114        impl PrimitiveSimdValue for $WideBoolF32xX {}
115
116        impl $WideF32xX {
117            pub const ZERO: Self = $WideF32xX(<wide::$f32xX>::ZERO);
118            pub const ONE: Self = $WideF32xX(<wide::$f32xX>::ONE);
119
120            #[inline(always)]
121            pub fn into_arr(self) -> [$f32; $lanes] {
122                self.0.into()
123            }
124
125            #[inline(always)]
126            pub fn from_arr(arr: [$f32; $lanes]) -> Self {
127                Self(arr.into())
128            }
129
130            #[inline(always)]
131            pub fn map(self, f: impl Fn($f32) -> $f32) -> Self {
132                let arr = self.into_arr();
133                Self::from([f(arr[0]), $(f(arr[$ii])),+])
134            }
135
136            #[inline(always)]
137            pub fn zip_map(self, rhs: Self, f: impl Fn($f32, $f32) -> $f32) -> Self {
138                let arr = self.into_arr();
139                let rhs = rhs.into_arr();
140                Self::from([
141                    f(arr[0], rhs[0]),
142                    $(f(arr[$ii], rhs[$ii])),+
143                ])
144            }
145        }
146
147        impl $WideBoolF32xX {
148            #[inline(always)]
149            pub fn from_arr(arr: [$f32; $lanes]) -> Self {
150                Self(arr.into())
151            }
152
153            #[inline(always)]
154            pub fn into_arr(self) -> [$f32; $lanes] {
155                self.0.into()
156            }
157        }
158
159        impl SimdValue for $WideF32xX {
160            const LANES: usize = $lanes;
161            type Element = $f32;
162            type SimdBool = $WideBoolF32xX;
163
164            #[inline(always)]
165            fn splat(val: Self::Element) -> Self {
166                // NOTE: we don’t use `wide::$f32xX::from(val)` because this results in
167                //       an inefficient `memset_pattern16` libc call.
168                $WideF32xX(wide::$f32xX::new([val, $({ let _ = $ii; val }),+]))
169            }
170
171            #[inline(always)]
172            fn extract(&self, i: usize) -> Self::Element {
173                self.into_arr()[i]
174            }
175
176            #[inline(always)]
177            unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
178                *self.into_arr().get_unchecked(i)
179            }
180
181            #[inline(always)]
182            fn replace(&mut self, i: usize, val: Self::Element) {
183                let mut arr = self.into_arr();
184                arr[i] = val;
185                *self = Self::from(arr);
186            }
187
188            #[inline(always)]
189            unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
190                let mut arr = self.into_arr();
191                *arr.get_unchecked_mut(i) = val;
192                *self = Self::from(arr);
193            }
194
195            #[inline(always)]
196            fn select(self, cond: Self::SimdBool, other: Self) -> Self {
197                $WideF32xX(cond.0.blend(self.0, other.0))
198            }
199        }
200
201        impl SimdValue for $WideBoolF32xX {
202            const LANES: usize = $lanes;
203            type Element = bool;
204            type SimdBool = Self;
205
206            #[inline(always)]
207            fn splat(val: bool) -> Self {
208                let results = [
209                    $WideBoolF32xX(wide::$f32xX::ZERO),
210                    $WideBoolF32xX(!wide::$f32xX::ZERO),
211                ];
212                results[val as usize]
213            }
214
215            #[inline(always)]
216            fn extract(&self, i: usize) -> Self::Element {
217                self.into_arr()[i] != 0.0
218            }
219
220            #[inline(always)]
221            unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
222                *self.into_arr().get_unchecked(i) != 0.0
223            }
224
225            #[inline(always)]
226            fn replace(&mut self, i: usize, val: Self::Element) {
227                let vals = [0.0, <$f32>::from_bits(Bounded::max_value())];
228                let mut arr = self.into_arr();
229                arr[i] = vals[val as usize];
230                *self = Self::from_arr(arr);
231            }
232
233            #[inline(always)]
234            unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
235                let vals = [0.0, <$f32>::from_bits(Bounded::max_value())];
236                let mut arr = self.into_arr();
237                *arr.get_unchecked_mut(i) = vals[val as usize];
238                *self = Self::from_arr(arr);
239            }
240
241            #[inline(always)]
242            fn select(self, cond: Self::SimdBool, other: Self) -> Self {
243                $WideBoolF32xX(cond.0.blend(self.0, other.0))
244            }
245        }
246
247        impl PartialEq for $WideF32xX {
248            #[inline]
249            fn eq(&self, rhs: &Self) -> bool {
250                self.0 == rhs.0
251            }
252        }
253
254        impl PartialEq for $WideBoolF32xX {
255            #[inline]
256            fn eq(&self, rhs: &Self) -> bool {
257                self.0 == rhs.0
258            }
259        }
260
261        impl Not for $WideBoolF32xX {
262            type Output = Self;
263
264            #[inline]
265            fn not(self) -> Self {
266                Self(!self.0)
267            }
268        }
269
270        impl BitXor for $WideBoolF32xX {
271            type Output = Self;
272
273            #[inline]
274            fn bitxor(self, rhs: Self) -> Self {
275                Self(self.0 ^ rhs.0)
276            }
277        }
278
279        impl BitOr for $WideBoolF32xX {
280            type Output = Self;
281
282            #[inline]
283            fn bitor(self, rhs: Self) -> Self {
284                Self(self.0 | rhs.0)
285            }
286        }
287
288        impl BitAnd for $WideBoolF32xX {
289            type Output = Self;
290
291            #[inline]
292            fn bitand(self, rhs: Self) -> Self {
293                Self(self.0 & rhs.0)
294            }
295        }
296
297        impl SimdBool for $WideBoolF32xX {
298            #[inline(always)]
299            fn bitmask(self) -> u64 {
300                let arr = self.into_arr();
301                (((arr[0] != 0.0) as u64) << 0)
302                    $(| (((arr[$ii] != 0.0) as u64) << $ii))*
303            }
304
305            #[inline(always)]
306            fn and(self) -> bool {
307                let arr = self.into_arr();
308                (arr[0].to_bits() $(& arr[$ii].to_bits())*) != 0
309            }
310
311            #[inline(always)]
312            fn or(self) -> bool {
313                let arr = self.into_arr();
314                (arr[0].to_bits() $(| arr[$ii].to_bits())*) != 0
315            }
316
317            #[inline(always)]
318            fn xor(self) -> bool {
319                let arr = self.into_arr();
320                (arr[0].to_bits() $(^ arr[$ii].to_bits())*) != 0
321            }
322
323            #[inline(always)]
324            fn all(self) -> bool {
325                self.0.all()
326            }
327
328            #[inline(always)]
329            fn any(self) -> bool {
330                self.0.any()
331            }
332
333            #[inline(always)]
334            fn none(self) -> bool {
335                self.0.none()
336            }
337
338            #[inline(always)]
339            fn if_else<Res: SimdValue<SimdBool = Self>>(
340                self,
341                if_value: impl FnOnce() -> Res,
342                else_value: impl FnOnce() -> Res,
343            ) -> Res {
344                let a = if_value();
345                let b = else_value();
346                a.select(self, b)
347            }
348
349            #[inline(always)]
350            fn if_else2<Res: SimdValue<SimdBool = Self>>(
351                self,
352                if_value: impl FnOnce() -> Res,
353                else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
354                else_value: impl FnOnce() -> Res,
355            ) -> Res {
356                let a = if_value();
357                let b = else_if.1();
358                let c = else_value();
359
360                let cond_a = self;
361                let cond_b = else_if.0();
362
363                a.select(cond_a, b.select(cond_b, c))
364            }
365
366            #[inline(always)]
367            fn if_else3<Res: SimdValue<SimdBool = Self>>(
368                self,
369                if_value: impl FnOnce() -> Res,
370                else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
371                else_else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
372                else_value: impl FnOnce() -> Res,
373            ) -> Res {
374                let a = if_value();
375                let b = else_if.1();
376                let c = else_else_if.1();
377                let d = else_value();
378
379                let cond_a = self;
380                let cond_b = else_if.0();
381                let cond_c = else_else_if.0();
382
383                a.select(cond_a, b.select(cond_b, c.select(cond_c, d)))
384            }
385        }
386
387        impl From<[$f32; $lanes]> for $WideF32xX {
388            #[inline(always)]
389            fn from(vals: [$f32; $lanes]) -> Self {
390                $WideF32xX(wide::$f32xX::from(vals))
391            }
392        }
393
394        impl From<$WideF32xX> for [$f32; $lanes] {
395            #[inline(always)]
396            fn from(val: $WideF32xX) -> [$f32; $lanes] {
397                val.0.into()
398            }
399        }
400
401        impl SubsetOf<$WideF32xX> for $WideF32xX {
402            #[inline(always)]
403            fn to_superset(&self) -> Self {
404                *self
405            }
406
407            #[inline(always)]
408            fn from_superset(element: &Self) -> Option<Self> {
409                Some(*element)
410            }
411
412            #[inline(always)]
413            fn from_superset_unchecked(element: &Self) -> Self {
414                *element
415            }
416
417            #[inline(always)]
418            fn is_in_subset(_: &Self) -> bool {
419                true
420            }
421        }
422
423        impl From<[bool; $lanes]> for $WideBoolF32xX {
424            #[inline(always)]
425            fn from(vals: [bool; $lanes]) -> Self {
426                let bits = [0.0, <$f32>::from_bits(Bounded::max_value())];
427                $WideBoolF32xX(wide::$f32xX::from([
428                    bits[vals[0] as usize],
429                    $(bits[vals[$ii] as usize]),*
430                ]))
431            }
432        }
433
434        impl SubsetOf<$WideBoolF32xX> for $WideBoolF32xX {
435            #[inline(always)]
436            fn to_superset(&self) -> Self {
437                *self
438            }
439
440            #[inline(always)]
441            fn from_superset(element: &Self) -> Option<Self> {
442                Some(*element)
443            }
444
445            #[inline(always)]
446            fn from_superset_unchecked(element: &Self) -> Self {
447                *element
448            }
449
450            #[inline(always)]
451            fn is_in_subset(_: &Self) -> bool {
452                true
453            }
454        }
455
456        impl Num for $WideF32xX {
457            type FromStrRadixErr = <$f32 as Num>::FromStrRadixErr;
458
459            #[inline(always)]
460            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
461                <$f32>::from_str_radix(str, radix).map(Self::splat)
462            }
463        }
464
465        impl FromPrimitive for $WideF32xX {
466            #[inline(always)]
467            fn from_i64(n: i64) -> Option<Self> {
468                <$f32>::from_i64(n).map(Self::splat)
469            }
470
471            #[inline(always)]
472            fn from_u64(n: u64) -> Option<Self> {
473                <$f32>::from_u64(n).map(Self::splat)
474            }
475
476            #[inline(always)]
477            fn from_isize(n: isize) -> Option<Self> {
478                <$f32>::from_isize(n).map(Self::splat)
479            }
480
481            #[inline(always)]
482            fn from_i8(n: i8) -> Option<Self> {
483                <$f32>::from_i8(n).map(Self::splat)
484            }
485
486            #[inline(always)]
487            fn from_i16(n: i16) -> Option<Self> {
488                <$f32>::from_i16(n).map(Self::splat)
489            }
490
491            #[inline(always)]
492            fn from_i32(n: i32) -> Option<Self> {
493                <$f32>::from_i32(n).map(Self::splat)
494            }
495
496            #[inline(always)]
497            fn from_usize(n: usize) -> Option<Self> {
498                <$f32>::from_usize(n).map(Self::splat)
499            }
500
501            #[inline(always)]
502            fn from_u8(n: u8) -> Option<Self> {
503                <$f32>::from_u8(n).map(Self::splat)
504            }
505
506            #[inline(always)]
507            fn from_u16(n: u16) -> Option<Self> {
508                <$f32>::from_u16(n).map(Self::splat)
509            }
510
511            #[inline(always)]
512            fn from_u32(n: u32) -> Option<Self> {
513                <$f32>::from_u32(n).map(Self::splat)
514            }
515
516            #[inline(always)]
517            fn from_f32(n: f32) -> Option<Self> {
518                <$f32>::from_f32(n).map(Self::splat)
519            }
520
521            #[inline(always)]
522            fn from_f64(n: f64) -> Option<Self> {
523                <$f32>::from_f64(n).map(Self::splat)
524            }
525        }
526
527        impl Zero for $WideF32xX {
528            #[inline(always)]
529            fn zero() -> Self {
530                <$WideF32xX>::splat(<$f32>::zero())
531            }
532
533            #[inline(always)]
534            fn is_zero(&self) -> bool {
535                *self == Self::zero()
536            }
537        }
538
539        impl One for $WideF32xX {
540            #[inline(always)]
541            fn one() -> Self {
542                <$WideF32xX>::splat(<$f32>::one())
543            }
544        }
545
546        impl Add<$WideF32xX> for $WideF32xX {
547            type Output = Self;
548
549            #[inline(always)]
550            fn add(self, rhs: Self) -> Self {
551                Self(self.0 + rhs.0)
552            }
553        }
554
555        impl Sub<$WideF32xX> for $WideF32xX {
556            type Output = Self;
557
558            #[inline(always)]
559            fn sub(self, rhs: Self) -> Self {
560                Self(self.0 - rhs.0)
561            }
562        }
563
564        impl Mul<$WideF32xX> for $WideF32xX {
565            type Output = Self;
566
567            #[inline(always)]
568            fn mul(self, rhs: Self) -> Self {
569                Self(self.0 * rhs.0)
570            }
571        }
572
573        impl Div<$WideF32xX> for $WideF32xX {
574            type Output = Self;
575
576            #[inline(always)]
577            fn div(self, rhs: Self) -> Self {
578                Self(self.0 / rhs.0)
579            }
580        }
581
582        impl Rem<$WideF32xX> for $WideF32xX {
583            type Output = Self;
584
585            #[inline(always)]
586            fn rem(self, rhs: Self) -> Self {
587                self.zip_map(rhs, |a, b| a % b)
588            }
589        }
590
591        impl AddAssign<$WideF32xX> for $WideF32xX {
592            #[inline(always)]
593            fn add_assign(&mut self, rhs: Self) {
594                self.0 += rhs.0
595            }
596        }
597
598        impl SubAssign<$WideF32xX> for $WideF32xX {
599            #[inline(always)]
600            fn sub_assign(&mut self, rhs: Self) {
601                self.0 -= rhs.0
602            }
603        }
604
605        impl DivAssign<$WideF32xX> for $WideF32xX {
606            #[inline(always)]
607            fn div_assign(&mut self, rhs: Self) {
608                self.0 /= rhs.0
609            }
610        }
611
612        impl MulAssign<$WideF32xX> for $WideF32xX {
613            #[inline(always)]
614            fn mul_assign(&mut self, rhs: Self) {
615                self.0 *= rhs.0
616            }
617        }
618
619        impl RemAssign<$WideF32xX> for $WideF32xX {
620            #[inline(always)]
621            fn rem_assign(&mut self, rhs: Self) {
622                *self = *self % rhs;
623            }
624        }
625
626        impl SimdPartialOrd for $WideF32xX {
627            #[inline(always)]
628            fn simd_gt(self, other: Self) -> Self::SimdBool {
629                $WideBoolF32xX(self.0.simd_gt(other.0))
630            }
631
632            #[inline(always)]
633            fn simd_lt(self, other: Self) -> Self::SimdBool {
634                $WideBoolF32xX(self.0.simd_lt(other.0))
635            }
636
637            #[inline(always)]
638            fn simd_ge(self, other: Self) -> Self::SimdBool {
639                $WideBoolF32xX(self.0.simd_ge(other.0))
640            }
641
642            #[inline(always)]
643            fn simd_le(self, other: Self) -> Self::SimdBool {
644                $WideBoolF32xX(self.0.simd_le(other.0))
645            }
646
647            #[inline(always)]
648            fn simd_eq(self, other: Self) -> Self::SimdBool {
649                $WideBoolF32xX(self.0.simd_eq(other.0))
650            }
651
652            #[inline(always)]
653            fn simd_ne(self, other: Self) -> Self::SimdBool {
654                $WideBoolF32xX(self.0.simd_ne(other.0))
655            }
656
657            #[inline(always)]
658            fn simd_max(self, other: Self) -> Self {
659                $WideF32xX(self.0.max(other.0))
660            }
661            #[inline(always)]
662            fn simd_min(self, other: Self) -> Self {
663                $WideF32xX(self.0.min(other.0))
664            }
665
666            #[inline(always)]
667            fn simd_clamp(self, min: Self, max: Self) -> Self {
668                self.simd_min(max).simd_max(min)
669            }
670
671            #[inline(always)]
672            fn simd_horizontal_min(self) -> Self::Element {
673                let arr = self.into_arr();
674                arr[0]$(.min(arr[$ii]))*
675            }
676
677            #[inline(always)]
678            fn simd_horizontal_max(self) -> Self::Element {
679                let arr = self.into_arr();
680                arr[0]$(.max(arr[$ii]))*
681            }
682        }
683
684        impl Neg for $WideF32xX {
685            type Output = Self;
686
687            #[inline(always)]
688            fn neg(self) -> Self {
689                Self(-self.0)
690            }
691        }
692
693        impl SimdSigned for $WideF32xX {
694            #[inline(always)]
695            fn simd_abs(&self) -> Self {
696                $WideF32xX(self.0.abs())
697            }
698
699            #[inline(always)]
700            fn simd_abs_sub(&self, other: &Self) -> Self {
701                $WideF32xX((self.0 - other.0).max(Self::zero().0))
702            }
703
704            #[inline(always)]
705            fn simd_signum(&self) -> Self {
706                // TODO: is there a more efficient way?
707                self.map(|x| x.signum())
708            }
709
710            #[inline(always)]
711            fn is_simd_positive(&self) -> Self::SimdBool {
712                self.simd_gt(Self::zero())
713            }
714
715            #[inline(always)]
716            fn is_simd_negative(&self) -> Self::SimdBool {
717                self.simd_lt(Self::zero())
718            }
719        }
720
721        impl Field for $WideF32xX {}
722
723        impl SimdRealField for $WideF32xX {
724            #[inline(always)]
725            fn simd_atan2(self, other: Self) -> Self {
726                self.zip_map_lanes(other, <$f32 as RealField>::atan2)
727            }
728
729            #[inline(always)]
730            fn simd_copysign(self, sign: Self) -> Self {
731                let neg_zero = <Self as SimdValue>::splat(-0.0).0;
732                $WideF32xX((neg_zero & sign.0) | ((!neg_zero) & self.0))
733            }
734
735            #[inline(always)]
736            fn simd_default_epsilon() -> Self {
737                Self::splat(<$f32>::default_epsilon())
738            }
739
740            #[inline(always)]
741            fn simd_pi() -> Self {
742                $WideF32xX(wide::$f32xX::PI)
743            }
744
745            #[inline(always)]
746            fn simd_two_pi() -> Self {
747                $WideF32xX(wide::$f32xX::PI + wide::$f32xX::PI)
748            }
749
750            #[inline(always)]
751            fn simd_frac_pi_2() -> Self {
752                $WideF32xX(wide::$f32xX::FRAC_PI_2)
753            }
754
755            #[inline(always)]
756            fn simd_frac_pi_3() -> Self {
757                $WideF32xX(wide::$f32xX::FRAC_PI_3)
758            }
759
760            #[inline(always)]
761            fn simd_frac_pi_4() -> Self {
762                $WideF32xX(wide::$f32xX::FRAC_PI_4)
763            }
764
765            #[inline(always)]
766            fn simd_frac_pi_6() -> Self {
767                $WideF32xX(wide::$f32xX::FRAC_PI_6)
768            }
769
770            #[inline(always)]
771            fn simd_frac_pi_8() -> Self {
772                $WideF32xX(wide::$f32xX::FRAC_PI_8)
773            }
774
775            #[inline(always)]
776            fn simd_frac_1_pi() -> Self {
777                $WideF32xX(wide::$f32xX::FRAC_1_PI)
778            }
779
780            #[inline(always)]
781            fn simd_frac_2_pi() -> Self {
782                $WideF32xX(wide::$f32xX::FRAC_2_PI)
783            }
784
785            #[inline(always)]
786            fn simd_frac_2_sqrt_pi() -> Self {
787                $WideF32xX(wide::$f32xX::FRAC_2_SQRT_PI)
788            }
789
790            #[inline(always)]
791            fn simd_e() -> Self {
792                $WideF32xX(wide::$f32xX::E)
793            }
794
795            #[inline(always)]
796            fn simd_log2_e() -> Self {
797                $WideF32xX(wide::$f32xX::LOG2_E)
798            }
799
800            #[inline(always)]
801            fn simd_log10_e() -> Self {
802                $WideF32xX(wide::$f32xX::LOG10_E)
803            }
804
805            #[inline(always)]
806            fn simd_ln_2() -> Self {
807                $WideF32xX(wide::$f32xX::LN_2)
808            }
809
810            #[inline(always)]
811            fn simd_ln_10() -> Self {
812                $WideF32xX(wide::$f32xX::LN_10)
813            }
814        }
815
816        impl SimdComplexField for $WideF32xX {
817            type SimdRealField = Self;
818
819            #[inline(always)]
820            fn simd_horizontal_sum(self) -> Self::Element {
821                self.0.reduce_add()
822            }
823
824            #[inline(always)]
825            fn simd_horizontal_product(self) -> Self::Element {
826                self.extract(0) $(* self.extract($ii))*
827            }
828
829            #[inline(always)]
830            fn from_simd_real(re: Self::SimdRealField) -> Self {
831                re
832            }
833
834            #[inline(always)]
835            fn simd_real(self) -> Self::SimdRealField {
836                self
837            }
838
839            #[inline(always)]
840            fn simd_imaginary(self) -> Self::SimdRealField {
841                Self::zero()
842            }
843
844            #[inline(always)]
845            fn simd_norm1(self) -> Self::SimdRealField {
846                $WideF32xX(self.0.abs())
847            }
848
849            #[inline(always)]
850            fn simd_modulus(self) -> Self::SimdRealField {
851                $WideF32xX(self.0.abs())
852            }
853
854            #[inline(always)]
855            fn simd_modulus_squared(self) -> Self::SimdRealField {
856                self * self
857            }
858
859            #[inline(always)]
860            fn simd_argument(self) -> Self::SimdRealField {
861                self.map_lanes(|e| e.argument())
862            }
863
864            #[inline(always)]
865            fn simd_to_exp(self) -> (Self::SimdRealField, Self) {
866                let ge = self.0.simd_ge(Self::one().0);
867                let exp = ge.blend(Self::one().0, -Self::one().0);
868                ($WideF32xX(self.0 * exp), $WideF32xX(exp))
869            }
870
871            #[inline(always)]
872            fn simd_recip(self) -> Self {
873                Self::one() / self
874            }
875
876            #[inline(always)]
877            fn simd_conjugate(self) -> Self {
878                self
879            }
880
881            #[inline(always)]
882            fn simd_scale(self, factor: Self::SimdRealField) -> Self {
883                $WideF32xX(self.0 * factor.0)
884            }
885
886            #[inline(always)]
887            fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
888                $WideF32xX(self.0 / factor.0)
889            }
890
891            #[inline(always)]
892            fn simd_floor(self) -> Self {
893                self.map_lanes(|e| e.floor())
894            }
895
896            #[inline(always)]
897            fn simd_ceil(self) -> Self {
898                self.map_lanes(|e| e.ceil())
899            }
900
901            #[inline(always)]
902            fn simd_round(self) -> Self {
903                self.map_lanes(|e| e.round())
904            }
905
906            #[inline(always)]
907            fn simd_trunc(self) -> Self {
908                self.map_lanes(|e| e.trunc())
909            }
910
911            #[inline(always)]
912            fn simd_fract(self) -> Self {
913                self.map_lanes(|e| e.fract())
914            }
915
916            #[inline(always)]
917            fn simd_abs(self) -> Self {
918                $WideF32xX(self.0.abs())
919            }
920
921            #[inline(always)]
922            fn simd_signum(self) -> Self {
923                self.map_lanes(|e| e.signum())
924            }
925
926            #[inline(always)]
927            fn simd_mul_add(self, a: Self, b: Self) -> Self {
928                $WideF32xX(self.0.mul_add(a.0, b.0))
929            }
930
931            #[inline(always)]
932            fn simd_powi(self, n: i32) -> Self {
933                self.map_lanes(|e| e.powi(n))
934            }
935
936            #[inline(always)]
937            fn simd_powf(self, n: Self) -> Self {
938                self.zip_map_lanes(n, <$f32 as ComplexField>::powf)
939            }
940
941            #[inline(always)]
942            fn simd_powc(self, n: Self) -> Self {
943                self.zip_map_lanes(n, <$f32 as ComplexField>::powf)
944            }
945
946            #[inline(always)]
947            fn simd_sqrt(self) -> Self {
948                $WideF32xX(self.0.sqrt())
949            }
950
951            #[inline(always)]
952            fn simd_exp(self) -> Self {
953                self.map_lanes(<$f32 as ComplexField>::exp)
954            }
955
956            #[inline(always)]
957            fn simd_exp2(self) -> Self {
958                self.map_lanes(<$f32 as ComplexField>::exp2)
959            }
960
961            #[inline(always)]
962            fn simd_exp_m1(self) -> Self {
963                self.map_lanes(<$f32 as ComplexField>::exp_m1)
964            }
965
966            #[inline(always)]
967            fn simd_ln_1p(self) -> Self {
968                self.map_lanes(<$f32 as ComplexField>::ln_1p)
969            }
970
971            #[inline(always)]
972            fn simd_ln(self) -> Self {
973                self.map_lanes(<$f32 as ComplexField>::ln)
974            }
975
976            #[inline(always)]
977            fn simd_log(self, base: Self) -> Self {
978                // Same formula as `std`'s `log`, per-lane.
979                self.zip_map_lanes(base, |e, b| <$f32 as ComplexField>::ln(e) / <$f32 as ComplexField>::ln(b))
980            }
981
982            #[inline(always)]
983            fn simd_log2(self) -> Self {
984                self.map_lanes(<$f32 as ComplexField>::log2)
985            }
986
987            #[inline(always)]
988            fn simd_log10(self) -> Self {
989                self.map_lanes(<$f32 as ComplexField>::log10)
990            }
991
992            #[inline(always)]
993            fn simd_cbrt(self) -> Self {
994                self.map_lanes(<$f32 as ComplexField>::cbrt)
995            }
996
997            #[inline(always)]
998            fn simd_hypot(self, other: Self) -> Self::SimdRealField {
999                self.zip_map_lanes(other, <$f32 as ComplexField>::hypot)
1000            }
1001
1002            // sin/cos/sin_cos keep wide's SIMD polynomial by default (it internally uses
1003            // `mul_add`, fused on NEON but not baseline x86 — fine without a determinism
1004            // requirement) and go per-lane through libm under `libm_force`.
1005            #[cfg(not(feature = "libm_force"))]
1006            #[inline(always)]
1007            fn simd_sin(self) -> Self {
1008                $WideF32xX(self.0.sin())
1009            }
1010
1011            #[cfg(feature = "libm_force")]
1012            #[inline(always)]
1013            fn simd_sin(self) -> Self {
1014                self.map_lanes(<$f32 as ComplexField>::sin)
1015            }
1016
1017            #[cfg(not(feature = "libm_force"))]
1018            #[inline(always)]
1019            fn simd_cos(self) -> Self {
1020                $WideF32xX(self.0.cos())
1021            }
1022
1023            #[cfg(feature = "libm_force")]
1024            #[inline(always)]
1025            fn simd_cos(self) -> Self {
1026                self.map_lanes(<$f32 as ComplexField>::cos)
1027            }
1028
1029            #[inline(always)]
1030            fn simd_tan(self) -> Self {
1031                self.map_lanes(<$f32 as ComplexField>::tan)
1032            }
1033
1034            #[inline(always)]
1035            fn simd_asin(self) -> Self {
1036                self.map_lanes(<$f32 as ComplexField>::asin)
1037            }
1038
1039            #[inline(always)]
1040            fn simd_acos(self) -> Self {
1041                self.map_lanes(<$f32 as ComplexField>::acos)
1042            }
1043
1044            #[inline(always)]
1045            fn simd_atan(self) -> Self {
1046                self.map_lanes(<$f32 as ComplexField>::atan)
1047            }
1048
1049            #[cfg(not(feature = "libm_force"))]
1050            #[inline(always)]
1051            fn simd_sin_cos(self) -> (Self, Self) {
1052                let (sin, cos) = self.0.sin_cos();
1053                ($WideF32xX(sin), $WideF32xX(cos))
1054            }
1055
1056            #[cfg(feature = "libm_force")]
1057            #[inline(always)]
1058            fn simd_sin_cos(self) -> (Self, Self) {
1059                let mut sin = self;
1060                let mut cos = self;
1061                for ii in 0..$lanes {
1062                    let (s, c) = <$f32 as ComplexField>::sin_cos(self.extract(ii));
1063                    sin.replace(ii, s);
1064                    cos.replace(ii, c);
1065                }
1066                (sin, cos)
1067            }
1068
1069            //            #[inline(always]
1070            //            fn simd_exp_m1(self) -> Self {
1071            //                <$f32 as ComplexField>::exp_m1(self)
1072            //            }
1073            //
1074            //            #[inline(always]
1075            //            fn simd_ln_1p(self) -> Self {
1076            //                <$f32 as ComplexField>::ln_1p(self)
1077            //            }
1078            //
1079            #[inline(always)]
1080            fn simd_sinh(self) -> Self {
1081                self.map_lanes(<$f32 as ComplexField>::sinh)
1082            }
1083
1084            #[inline(always)]
1085            fn simd_cosh(self) -> Self {
1086                self.map_lanes(<$f32 as ComplexField>::cosh)
1087            }
1088
1089            #[inline(always)]
1090            fn simd_tanh(self) -> Self {
1091                self.map_lanes(<$f32 as ComplexField>::tanh)
1092            }
1093
1094            #[inline(always)]
1095            fn simd_asinh(self) -> Self {
1096                self.map_lanes(<$f32 as ComplexField>::asinh)
1097            }
1098
1099            #[inline(always)]
1100            fn simd_acosh(self) -> Self {
1101                self.map_lanes(<$f32 as ComplexField>::acosh)
1102            }
1103
1104            #[inline(always)]
1105            fn simd_atanh(self) -> Self {
1106                self.map_lanes(<$f32 as ComplexField>::atanh)
1107            }
1108        }
1109
1110        // NOTE: most of the impls in there are copy-paste from the implementation of
1111        // ComplexField for num_complex::Complex. Unfortunately, we can't reuse the implementations
1112        // so easily.
1113        impl SimdComplexField for num_complex::Complex<$WideF32xX> {
1114            type SimdRealField = $WideF32xX;
1115
1116            #[inline(always)]
1117            fn simd_horizontal_sum(self) -> Self::Element {
1118                num_complex::Complex::new(self.re.simd_horizontal_sum(), self.im.simd_horizontal_sum())
1119            }
1120
1121            #[inline(always)]
1122            fn simd_horizontal_product(self) -> Self::Element {
1123                let mut prod = self.extract(0);
1124                for ii in 1..Self::LANES {
1125                    prod *= self.extract(ii)
1126                }
1127                prod
1128            }
1129
1130            #[inline]
1131            fn from_simd_real(re: Self::SimdRealField) -> Self {
1132                Self::new(re, Self::SimdRealField::zero())
1133            }
1134
1135            #[inline]
1136            fn simd_real(self) -> Self::SimdRealField {
1137                self.re
1138            }
1139
1140            #[inline]
1141            fn simd_imaginary(self) -> Self::SimdRealField {
1142                self.im
1143            }
1144
1145            #[inline]
1146            fn simd_argument(self) -> Self::SimdRealField {
1147                self.im.simd_atan2(self.re)
1148            }
1149
1150            #[inline]
1151            fn simd_modulus(self) -> Self::SimdRealField {
1152                self.re.simd_hypot(self.im)
1153            }
1154
1155            #[inline]
1156            fn simd_modulus_squared(self) -> Self::SimdRealField {
1157                self.re * self.re + self.im * self.im
1158            }
1159
1160            #[inline]
1161            fn simd_norm1(self) -> Self::SimdRealField {
1162                self.re.simd_abs() + self.im.simd_abs()
1163            }
1164
1165            #[inline]
1166            fn simd_recip(self) -> Self {
1167                Self::one() / self
1168            }
1169
1170            #[inline]
1171            fn simd_conjugate(self) -> Self {
1172                self.conj()
1173            }
1174
1175            #[inline]
1176            fn simd_scale(self, factor: Self::SimdRealField) -> Self {
1177                self * factor
1178            }
1179
1180            #[inline]
1181            fn simd_unscale(self, factor: Self::SimdRealField) -> Self {
1182                self / factor
1183            }
1184
1185            #[inline]
1186            fn simd_floor(self) -> Self {
1187                Self::new(self.re.simd_floor(), self.im.simd_floor())
1188            }
1189
1190            #[inline]
1191            fn simd_ceil(self) -> Self {
1192                Self::new(self.re.simd_ceil(), self.im.simd_ceil())
1193            }
1194
1195            #[inline]
1196            fn simd_round(self) -> Self {
1197                Self::new(self.re.simd_round(), self.im.simd_round())
1198            }
1199
1200            #[inline]
1201            fn simd_trunc(self) -> Self {
1202                Self::new(self.re.simd_trunc(), self.im.simd_trunc())
1203            }
1204
1205            #[inline]
1206            fn simd_fract(self) -> Self {
1207                Self::new(self.re.simd_fract(), self.im.simd_fract())
1208            }
1209
1210            #[inline]
1211            fn simd_mul_add(self, a: Self, b: Self) -> Self {
1212                self * a + b
1213            }
1214
1215            #[inline]
1216            fn simd_abs(self) -> Self::SimdRealField {
1217                self.simd_modulus()
1218            }
1219
1220            #[inline]
1221            fn simd_exp2(self) -> Self {
1222                let _2 = <$WideF32xX>::one() + <$WideF32xX>::one();
1223                num_complex::Complex::new(_2, <$WideF32xX>::zero()).simd_powc(self)
1224            }
1225
1226            #[inline]
1227            fn simd_exp_m1(self) -> Self {
1228                self.simd_exp() - Self::one()
1229            }
1230
1231            #[inline]
1232            fn simd_ln_1p(self) -> Self {
1233                (Self::one() + self).simd_ln()
1234            }
1235
1236            #[inline]
1237            fn simd_log2(self) -> Self {
1238                let _2 = <$WideF32xX>::one() + <$WideF32xX>::one();
1239                self.simd_log(_2)
1240            }
1241
1242            #[inline]
1243            fn simd_log10(self) -> Self {
1244                let _10 = <$WideF32xX>::from_subset(&10.0f64);
1245                self.simd_log(_10)
1246            }
1247
1248            #[inline]
1249            fn simd_cbrt(self) -> Self {
1250                let one_third = <$WideF32xX>::from_subset(&(1.0 / 3.0));
1251                self.simd_powf(one_third)
1252            }
1253
1254            #[inline]
1255            fn simd_powi(self, n: i32) -> Self {
1256                // TODO: is there a more accurate solution?
1257                let n = <$WideF32xX>::from_subset(&(n as f64));
1258                self.simd_powf(n)
1259            }
1260
1261            /*
1262            *
1263            *
1264            * Unfortunately we are forced to copy-paste all
1265            * those impls from https://github.com/rust-num/num-complex/blob/master/src/lib.rs
1266            * to avoid requiring `std`.
1267            *
1268            *
1269            */
1270            /// Computes `e^(self)`, where `e` is the base of the natural logarithm.
1271            #[inline]
1272            fn simd_exp(self) -> Self {
1273                // formula: e^(a + bi) = e^a (cos(b) + i*sin(b))
1274                // = from_polar(e^a, b)
1275                simd_complex_from_polar(self.re.simd_exp(), self.im)
1276            }
1277
1278            /// Computes the principal value of natural logarithm of `self`.
1279            ///
1280            /// This function has one branch cut:
1281            ///
1282            /// * `(-∞, 0]`, continuous from above.
1283            ///
1284            /// The branch satisfies `-π ≤ arg(ln(z)) ≤ π`.
1285            #[inline]
1286            fn simd_ln(self) -> Self {
1287                // formula: ln(z) = ln|z| + i*arg(z)
1288                let (r, theta) = self.simd_to_polar();
1289                Self::new(r.simd_ln(), theta)
1290            }
1291
1292            /// Computes the principal value of the square root of `self`.
1293            ///
1294            /// This function has one branch cut:
1295            ///
1296            /// * `(-∞, 0)`, continuous from above.
1297            ///
1298            /// The branch satisfies `-π/2 ≤ arg(sqrt(z)) ≤ π/2`.
1299            #[inline]
1300            fn simd_sqrt(self) -> Self {
1301                // formula: sqrt(r e^(it)) = sqrt(r) e^(it/2)
1302                let two = <$WideF32xX>::one() + <$WideF32xX>::one();
1303                let (r, theta) = self.simd_to_polar();
1304                simd_complex_from_polar(r.simd_sqrt(), theta / two)
1305            }
1306
1307            #[inline]
1308            fn simd_hypot(self, b: Self) -> Self::SimdRealField {
1309                (self.simd_modulus_squared() + b.simd_modulus_squared()).simd_sqrt()
1310            }
1311
1312            /// Raises `self` to a floating point power.
1313            #[inline]
1314            fn simd_powf(self, exp: Self::SimdRealField) -> Self {
1315                // formula: x^y = (ρ e^(i θ))^y = ρ^y e^(i θ y)
1316                // = from_polar(ρ^y, θ y)
1317                let (r, theta) = self.simd_to_polar();
1318                simd_complex_from_polar(r.simd_powf(exp), theta * exp)
1319            }
1320
1321            /// Returns the logarithm of `self` with respect to an arbitrary base.
1322            #[inline]
1323            fn simd_log(self, base: $WideF32xX) -> Self {
1324                // formula: log_y(x) = log_y(ρ e^(i θ))
1325                // = log_y(ρ) + log_y(e^(i θ)) = log_y(ρ) + ln(e^(i θ)) / ln(y)
1326                // = log_y(ρ) + i θ / ln(y)
1327                let (r, theta) = self.simd_to_polar();
1328                Self::new(r.simd_log(base), theta / base.simd_ln())
1329            }
1330
1331            /// Raises `self` to a complex power.
1332            #[inline]
1333            fn simd_powc(self, exp: Self) -> Self {
1334                // formula: x^y = (a + i b)^(c + i d)
1335                // = (ρ e^(i θ))^c (ρ e^(i θ))^(i d)
1336                //    where ρ=|x| and θ=arg(x)
1337                // = ρ^c e^(−d θ) e^(i c θ) ρ^(i d)
1338                // = p^c e^(−d θ) (cos(c θ)
1339                //   + i sin(c θ)) (cos(d ln(ρ)) + i sin(d ln(ρ)))
1340                // = p^c e^(−d θ) (
1341                //   cos(c θ) cos(d ln(ρ)) − sin(c θ) sin(d ln(ρ))
1342                //   + i(cos(c θ) sin(d ln(ρ)) + sin(c θ) cos(d ln(ρ))))
1343                // = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ)))
1344                // = from_polar(p^c e^(−d θ), c θ + d ln(ρ))
1345                let (r, theta) = self.simd_to_polar();
1346                simd_complex_from_polar(
1347                    r.simd_powf(exp.re) * (-exp.im * theta).simd_exp(),
1348                    exp.re * theta + exp.im * r.simd_ln(),
1349                )
1350            }
1351
1352            /*
1353            /// Raises a floating point number to the complex power `self`.
1354            #[inline]
1355            fn simd_expf(&self, base: T) -> Self {
1356                // formula: x^(a+bi) = x^a x^bi = x^a e^(b ln(x) i)
1357                // = from_polar(x^a, b ln(x))
1358                Self::from_polar(&base.powf(self.re), &(self.im * base.ln()))
1359            }
1360            */
1361
1362            /// Computes the sine of `self`.
1363            #[inline]
1364            fn simd_sin(self) -> Self {
1365                // formula: sin(a + bi) = sin(a)cosh(b) + i*cos(a)sinh(b)
1366                Self::new(
1367                    self.re.simd_sin() * self.im.simd_cosh(),
1368                    self.re.simd_cos() * self.im.simd_sinh(),
1369                )
1370            }
1371
1372            /// Computes the cosine of `self`.
1373            #[inline]
1374            fn simd_cos(self) -> Self {
1375                // formula: cos(a + bi) = cos(a)cosh(b) - i*sin(a)sinh(b)
1376                Self::new(
1377                    self.re.simd_cos() * self.im.simd_cosh(),
1378                    -self.re.simd_sin() * self.im.simd_sinh(),
1379                )
1380            }
1381
1382            #[inline]
1383            fn simd_sin_cos(self) -> (Self, Self) {
1384                let (rsin, rcos) = self.re.simd_sin_cos();
1385                let (isinh, icosh) = self.im.simd_sinh_cosh();
1386                let sin = Self::new(rsin * icosh, rcos * isinh);
1387                let cos = Self::new(rcos * icosh, -rsin * isinh);
1388
1389                (sin, cos)
1390            }
1391
1392            /// Computes the tangent of `self`.
1393            #[inline]
1394            fn simd_tan(self) -> Self {
1395                // formula: tan(a + bi) = (sin(2a) + i*sinh(2b))/(cos(2a) + cosh(2b))
1396                let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1397                Self::new(two_re.simd_sin(), two_im.simd_sinh())
1398                    .unscale(two_re.simd_cos() + two_im.simd_cosh())
1399            }
1400
1401            /// Computes the principal value of the inverse sine of `self`.
1402            ///
1403            /// This function has two branch cuts:
1404            ///
1405            /// * `(-∞, -1)`, continuous from above.
1406            /// * `(1, ∞)`, continuous from below.
1407            ///
1408            /// The branch satisfies `-π/2 ≤ Re(asin(z)) ≤ π/2`.
1409            #[inline]
1410            fn simd_asin(self) -> Self {
1411                // formula: arcsin(z) = -i ln(sqrt(1-z^2) + iz)
1412                let i = Self::i();
1413                -i * ((Self::one() - self * self).simd_sqrt() + i * self).simd_ln()
1414            }
1415
1416            /// Computes the principal value of the inverse cosine of `self`.
1417            ///
1418            /// This function has two branch cuts:
1419            ///
1420            /// * `(-∞, -1)`, continuous from above.
1421            /// * `(1, ∞)`, continuous from below.
1422            ///
1423            /// The branch satisfies `0 ≤ Re(acos(z)) ≤ π`.
1424            #[inline]
1425            fn simd_acos(self) -> Self {
1426                // formula: arccos(z) = -i ln(i sqrt(1-z^2) + z)
1427                let i = Self::i();
1428                -i * (i * (Self::one() - self * self).simd_sqrt() + self).simd_ln()
1429            }
1430
1431            /// Computes the principal value of the inverse tangent of `self`.
1432            ///
1433            /// This function has two branch cuts:
1434            ///
1435            /// * `(-∞i, -i]`, continuous from the left.
1436            /// * `[i, ∞i)`, continuous from the right.
1437            ///
1438            /// The branch satisfies `-π/2 ≤ Re(atan(z)) ≤ π/2`.
1439            #[inline]
1440            fn simd_atan(self) -> Self {
1441                // formula: arctan(z) = (ln(1+iz) - ln(1-iz))/(2i)
1442                let i = Self::i();
1443                let one = Self::one();
1444                let two = one + one;
1445
1446                if self == i {
1447                    return Self::new(<$WideF32xX>::zero(), <$WideF32xX>::one() / <$WideF32xX>::zero());
1448                } else if self == -i {
1449                    return Self::new(<$WideF32xX>::zero(), -<$WideF32xX>::one() / <$WideF32xX>::zero());
1450                }
1451
1452                ((one + i * self).simd_ln() - (one - i * self).simd_ln()) / (two * i)
1453            }
1454
1455            /// Computes the hyperbolic sine of `self`.
1456            #[inline]
1457            fn simd_sinh(self) -> Self {
1458                // formula: sinh(a + bi) = sinh(a)cos(b) + i*cosh(a)sin(b)
1459                Self::new(
1460                    self.re.simd_sinh() * self.im.simd_cos(),
1461                    self.re.simd_cosh() * self.im.simd_sin(),
1462                )
1463            }
1464
1465            /// Computes the hyperbolic cosine of `self`.
1466            #[inline]
1467            fn simd_cosh(self) -> Self {
1468                // formula: cosh(a + bi) = cosh(a)cos(b) + i*sinh(a)sin(b)
1469                Self::new(
1470                    self.re.simd_cosh() * self.im.simd_cos(),
1471                    self.re.simd_sinh() * self.im.simd_sin(),
1472                )
1473            }
1474
1475            #[inline]
1476            fn simd_sinh_cosh(self) -> (Self, Self) {
1477                let (rsinh, rcosh) = self.re.simd_sinh_cosh();
1478                let (isin, icos) = self.im.simd_sin_cos();
1479                let sin = Self::new(rsinh * icos, rcosh * isin);
1480                let cos = Self::new(rcosh * icos, rsinh * isin);
1481
1482                (sin, cos)
1483            }
1484
1485            /// Computes the hyperbolic tangent of `self`.
1486            #[inline]
1487            fn simd_tanh(self) -> Self {
1488                // formula: tanh(a + bi) = (sinh(2a) + i*sin(2b))/(cosh(2a) + cos(2b))
1489                let (two_re, two_im) = (self.re + self.re, self.im + self.im);
1490                Self::new(two_re.simd_sinh(), two_im.simd_sin())
1491                    .unscale(two_re.simd_cosh() + two_im.simd_cos())
1492            }
1493
1494            /// Computes the principal value of inverse hyperbolic sine of `self`.
1495            ///
1496            /// This function has two branch cuts:
1497            ///
1498            /// * `(-∞i, -i)`, continuous from the left.
1499            /// * `(i, ∞i)`, continuous from the right.
1500            ///
1501            /// The branch satisfies `-π/2 ≤ Im(asinh(z)) ≤ π/2`.
1502            #[inline]
1503            fn simd_asinh(self) -> Self {
1504                // formula: arcsinh(z) = ln(z + sqrt(1+z^2))
1505                let one = Self::one();
1506                (self + (one + self * self).simd_sqrt()).simd_ln()
1507            }
1508
1509            /// Computes the principal value of inverse hyperbolic cosine of `self`.
1510            ///
1511            /// This function has one branch cut:
1512            ///
1513            /// * `(-∞, 1)`, continuous from above.
1514            ///
1515            /// The branch satisfies `-π ≤ Im(acosh(z)) ≤ π` and `0 ≤ Re(acosh(z)) < ∞`.
1516            #[inline]
1517            fn simd_acosh(self) -> Self {
1518                // formula: arccosh(z) = 2 ln(sqrt((z+1)/2) + sqrt((z-1)/2))
1519                let one = Self::one();
1520                let two = one + one;
1521                two * (((self + one) / two).simd_sqrt() + ((self - one) / two).simd_sqrt()).simd_ln()
1522            }
1523
1524            /// Computes the principal value of inverse hyperbolic tangent of `self`.
1525            ///
1526            /// This function has two branch cuts:
1527            ///
1528            /// * `(-∞, -1]`, continuous from above.
1529            /// * `[1, ∞)`, continuous from below.
1530            ///
1531            /// The branch satisfies `-π/2 ≤ Im(atanh(z)) ≤ π/2`.
1532            #[inline]
1533            fn simd_atanh(self) -> Self {
1534                // formula: arctanh(z) = (ln(1+z) - ln(1-z))/2
1535                let one = Self::one();
1536                let two = one + one;
1537                if self == one {
1538                    return Self::new(<$WideF32xX>::one() / <$WideF32xX>::zero(), <$WideF32xX>::zero());
1539                } else if self == -one {
1540                    return Self::new(-<$WideF32xX>::one() / <$WideF32xX>::zero(), <$WideF32xX>::zero());
1541                }
1542                ((one + self).simd_ln() - (one - self).simd_ln()) / two
1543            }
1544        }
1545    }
1546);
1547
1548macro_rules! impl_scalar_subset_of_simd (
1549    ($WideF32xX: ty, $f32: ty, $lanes: expr; $($t: ty),*) => {$(
1550        impl SubsetOf<$WideF32xX> for $t {
1551            #[inline(always)]
1552            fn to_superset(&self) -> $WideF32xX {
1553                <$WideF32xX>::splat(<$f32>::from_subset(self))
1554            }
1555
1556            #[inline(always)]
1557            fn from_superset_unchecked(element: &$WideF32xX) -> $t {
1558                element.extract(0).to_subset_unchecked()
1559            }
1560
1561            #[inline(always)]
1562            fn is_in_subset(c: &$WideF32xX) -> bool {
1563                let elt0 = c.extract(0);
1564                <$t as SubsetOf<$f32>>::is_in_subset(&elt0) &&
1565                (1..$lanes).all(|i| c.extract(i) == elt0)
1566            }
1567        }
1568    )*}
1569);
1570
1571impl_scalar_subset_of_simd!(WideF32x4, f32, 4; u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
1572impl_scalar_subset_of_simd!(WideF64x4, f64, 4; u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
1573//#[cfg(feature = "decimal")]
1574//impl_scalar_subset_of_simd!(WideF32x4, 4; d128);
1575impl_scalar_subset_of_simd!(WideF32x8, f32, 8; u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
1576//#[cfg(feature = "decimal")]
1577//impl_scalar_subset_of_simd!(WideF32x8, 8; d128);
1578
1579// NOTE: don’t include the 0 for the indices because they are taken care
1580// for explicitly in the macro (it’s simpler that way).
1581impl_wide_f32!(f32, f32x4, WideF32x4, WideBoolF32x4, 4; 1, 2, 3);
1582impl_wide_f32!(f64, f64x4, WideF64x4, WideBoolF64x4, 4; 1, 2, 3);
1583impl_wide_f32!(f32, f32x8, WideF32x8, WideBoolF32x8, 8; 1, 2, 3, 4, 5, 6, 7);
1584
1585#[inline]
1586fn simd_complex_from_polar<N: SimdRealField>(r: N, theta: N) -> num_complex::Complex<N> {
1587    num_complex::Complex::new(r.clone() * theta.clone().simd_cos(), r * theta.simd_sin())
1588}