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