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