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