faer_core/complex_native/
c32_impl.rs

1use crate::complex_native::c32conj_impl::c32conj;
2use faer_entity::*;
3#[cfg(not(feature = "std"))]
4use num_traits::float::FloatCore;
5
6use num_traits::{One, Zero};
7use pulp::{cast, Simd};
8
9#[cfg(feature = "std")]
10use num_complex::ComplexFloat;
11
12#[cfg(feature = "std")]
13macro_rules! impl_from_num_complex {
14    ($( $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) => {
15        $(
16            #[inline(always)]
17            #[allow(missing_docs)]
18            pub fn $method(self $( , $arg : $ty )* ) -> $ret {
19                self.to_num_complex().$method( $( $arg , )* ).into()
20            }
21        )*
22    };
23}
24
25/// 32-bit complex floating point type. See the module-level documentation for more details.
26#[allow(non_camel_case_types)]
27#[derive(Copy, Clone, PartialEq)]
28#[repr(C)]
29pub struct c32 {
30    /// Real part.
31    pub re: f32,
32    /// Imaginary part.
33    pub im: f32,
34}
35
36impl c32 {
37    /// Create a new complex number.
38    #[inline(always)]
39    pub fn new(re: f32, im: f32) -> Self {
40        Self { re, im }
41    }
42
43    /// Construct the imaginary number.
44    #[inline(always)]
45    pub fn i() -> Self {
46        Self::new(0.0, 1.0)
47    }
48
49    /// Create a complex number from a phase.
50    #[cfg(feature = "std")]
51    #[inline(always)]
52    pub fn cis(phase: f32) -> Self {
53        Self::new(phase.cos(), phase.sin())
54    }
55
56    /// Create a complex number from polar coordinates.
57    #[cfg(feature = "std")]
58    #[inline(always)]
59    pub fn from_polar(r: f32, theta: f32) -> Self {
60        Self::new(r * theta.cos(), r * theta.sin())
61    }
62
63    /// Convert the number to a num_complex::Complex32.
64    #[inline(always)]
65    pub fn to_num_complex(self) -> num_complex::Complex<f32> {
66        self.into()
67    }
68
69    /// Returns the real part of the complex number.
70    #[inline(always)]
71    pub fn re(self) -> f32 {
72        self.re
73    }
74
75    /// Returns the imaginary part of the complex number.
76    #[inline(always)]
77    pub fn im(self) -> f32 {
78        self.im
79    }
80
81    /// Calculate the complex conjugate of self.
82    #[inline(always)]
83    pub fn conj(self) -> Self {
84        self.faer_conj()
85    }
86
87    #[cfg(feature = "std")]
88    impl_from_num_complex!(
89        is_nan(self) -> bool;
90        is_infinite(self) -> bool;
91        is_finite(self) -> bool;
92        is_normal(self) -> bool;
93        recip(self) -> Self;
94        powi(self, exp: i32) -> Self;
95        powu(self, exp: u32) -> Self;
96        powf(self, exp: f32) -> Self;
97        powc(self, exp: num_complex::Complex<f32>) -> Self;
98        sqrt(self) -> Self;
99        exp(self) -> Self;
100        exp2(self) -> Self;
101        expf(self, base: f32) -> Self;
102        ln(self) -> Self;
103        log(self, base: f32) -> Self;
104        log2(self) -> Self;
105        log10(self) -> Self;
106        cbrt(self) -> Self;
107        sin(self) -> Self;
108        cos(self) -> Self;
109        tan(self) -> Self;
110        asin(self) -> Self;
111        acos(self) -> Self;
112        atan(self) -> Self;
113        sinh(self) -> Self;
114        cosh(self) -> Self;
115        tanh(self) -> Self;
116        asinh(self) -> Self;
117        acosh(self) -> Self;
118        atanh(self) -> Self;
119        abs(self) -> f32;
120        arg(self) -> f32;
121    );
122
123    /// Computes the `l2` norm of `self`.
124    #[inline(always)]
125    pub fn norm(&self) -> f32 {
126        self.faer_abs()
127    }
128
129    /// Computes the `l1` norm of `self`.
130    #[inline(always)]
131    pub fn l1_norm(&self) -> f32 {
132        self.re.faer_abs() + self.im.faer_abs()
133    }
134
135    /// Computes the squared `l2` norm of `self`.
136    #[inline(always)]
137    pub fn norm_sqr(&self) -> f32 {
138        self.faer_abs2()
139    }
140
141    /// Computes the inverse of `self`.
142    #[inline(always)]
143    pub fn inv(&self) -> Self {
144        let norm_sqr = self.faer_abs2();
145        Self::new(self.re / norm_sqr, -self.im / norm_sqr)
146    }
147}
148
149impl Zero for c32 {
150    #[inline(always)]
151    fn zero() -> Self {
152        Self::new(0.0, 0.0)
153    }
154
155    #[inline(always)]
156    fn is_zero(&self) -> bool {
157        self.re.is_zero() && self.im.is_zero()
158    }
159
160    #[inline(always)]
161    fn set_zero(&mut self) {
162        self.re.set_zero();
163        self.im.set_zero();
164    }
165}
166
167impl One for c32 {
168    #[inline(always)]
169    fn one() -> Self {
170        Self::new(1.0, 0.0)
171    }
172
173    #[inline(always)]
174    fn is_one(&self) -> bool {
175        self.re.is_one() && self.im.is_zero()
176    }
177
178    #[inline(always)]
179    fn set_one(&mut self) {
180        self.re.set_one();
181        self.im.set_zero();
182    }
183}
184
185impl core::ops::Neg for c32 {
186    type Output = c32;
187
188    #[inline(always)]
189    fn neg(self) -> Self::Output {
190        Self::new(-self.re, -self.im)
191    }
192}
193
194impl core::ops::Add<f32> for c32 {
195    type Output = c32;
196
197    #[inline(always)]
198    fn add(self, rhs: f32) -> Self::Output {
199        Self::new(self.re + rhs, self.im)
200    }
201}
202
203impl core::ops::Add<c32> for f32 {
204    type Output = c32;
205
206    #[inline(always)]
207    fn add(self, rhs: c32) -> Self::Output {
208        Self::Output::new(self + rhs.re, rhs.im)
209    }
210}
211
212impl core::ops::Add for c32 {
213    type Output = c32;
214
215    #[inline(always)]
216    fn add(self, rhs: Self) -> Self::Output {
217        Self::new(self.re + rhs.re, self.im + rhs.im)
218    }
219}
220
221impl core::ops::Add<c32conj> for c32 {
222    type Output = c32;
223
224    #[inline(always)]
225    fn add(self, rhs: c32conj) -> Self::Output {
226        Self::new(self.re + rhs.re, self.im - rhs.neg_im)
227    }
228}
229
230impl core::ops::Add<c32> for c32conj {
231    type Output = c32;
232
233    #[inline(always)]
234    fn add(self, rhs: c32) -> Self::Output {
235        Self::Output::new(self.re + rhs.re, rhs.im - self.neg_im)
236    }
237}
238
239impl core::ops::Sub<f32> for c32 {
240    type Output = c32;
241
242    #[inline(always)]
243    fn sub(self, rhs: f32) -> Self::Output {
244        Self::new(self.re - rhs, self.im)
245    }
246}
247
248impl core::ops::Sub<c32> for f32 {
249    type Output = c32;
250
251    #[inline(always)]
252    fn sub(self, rhs: c32) -> Self::Output {
253        Self::Output::new(self - rhs.re, -rhs.im)
254    }
255}
256
257impl core::ops::Sub for c32 {
258    type Output = c32;
259
260    #[inline(always)]
261    fn sub(self, rhs: Self) -> Self::Output {
262        Self::new(self.re - rhs.re, self.im - rhs.im)
263    }
264}
265
266impl core::ops::Sub<c32conj> for c32 {
267    type Output = c32;
268
269    #[inline(always)]
270    fn sub(self, rhs: c32conj) -> Self::Output {
271        Self::new(self.re - rhs.re, self.im + rhs.neg_im)
272    }
273}
274
275impl core::ops::Sub<c32> for c32conj {
276    type Output = c32;
277
278    #[inline(always)]
279    fn sub(self, rhs: c32) -> Self::Output {
280        Self::Output::new(self.re - rhs.re, -self.neg_im - rhs.im)
281    }
282}
283
284impl core::ops::Mul<f32> for c32 {
285    type Output = c32;
286
287    #[inline(always)]
288    fn mul(self, rhs: f32) -> Self::Output {
289        Self::new(self.re * rhs, self.im * rhs)
290    }
291}
292
293impl core::ops::Mul<c32> for f32 {
294    type Output = c32;
295
296    #[inline(always)]
297    fn mul(self, rhs: c32) -> Self::Output {
298        Self::Output::new(self * rhs.re, self * rhs.im)
299    }
300}
301
302impl core::ops::Mul for c32 {
303    type Output = c32;
304
305    #[inline(always)]
306    fn mul(self, rhs: Self) -> Self::Output {
307        Self::new(
308            self.re * rhs.re - self.im * rhs.im,
309            self.re * rhs.im + self.im * rhs.re,
310        )
311    }
312}
313
314impl core::ops::Mul<c32conj> for c32 {
315    type Output = c32;
316
317    #[inline(always)]
318    fn mul(self, rhs: c32conj) -> Self::Output {
319        Self::new(
320            self.re * rhs.re + self.im * rhs.neg_im,
321            self.im * rhs.re - self.re * rhs.neg_im,
322        )
323    }
324}
325
326impl core::ops::Mul<c32> for c32conj {
327    type Output = c32;
328
329    #[inline(always)]
330    fn mul(self, rhs: c32) -> Self::Output {
331        Self::Output::new(
332            self.re * rhs.re + self.neg_im * rhs.im,
333            rhs.im * self.re - rhs.re * self.neg_im,
334        )
335    }
336}
337
338impl core::ops::Div<f32> for c32 {
339    type Output = c32;
340
341    #[inline(always)]
342    fn div(self, rhs: f32) -> Self::Output {
343        Self::new(self.re / rhs, self.im / rhs)
344    }
345}
346
347impl core::ops::Div<c32> for f32 {
348    type Output = c32;
349
350    #[allow(clippy::suspicious_arithmetic_impl)]
351    #[inline(always)]
352    fn div(self, rhs: c32) -> Self::Output {
353        self * rhs.faer_inv()
354    }
355}
356
357impl core::ops::Div for c32 {
358    type Output = c32;
359
360    #[allow(clippy::suspicious_arithmetic_impl)]
361    #[inline(always)]
362    fn div(self, rhs: Self) -> Self::Output {
363        self * rhs.faer_inv()
364    }
365}
366
367impl core::ops::Div<c32conj> for c32 {
368    type Output = c32;
369
370    #[allow(clippy::suspicious_arithmetic_impl)]
371    #[inline(always)]
372    fn div(self, rhs: c32conj) -> Self::Output {
373        self * rhs.canonicalize().faer_inv()
374    }
375}
376
377impl core::ops::Div<c32> for c32conj {
378    type Output = c32;
379
380    #[allow(clippy::suspicious_arithmetic_impl)]
381    #[inline(always)]
382    fn div(self, rhs: c32) -> Self::Output {
383        self * rhs.faer_inv()
384    }
385}
386
387impl core::ops::Rem<f32> for c32 {
388    type Output = c32;
389
390    #[inline(always)]
391    fn rem(self, rhs: f32) -> Self::Output {
392        Self::new(self.re % rhs, self.im % rhs)
393    }
394}
395
396impl core::ops::Rem<c32> for f32 {
397    type Output = c32;
398
399    #[inline(always)]
400    fn rem(self, rhs: c32) -> Self::Output {
401        self.rem(rhs.to_num_complex()).into()
402    }
403}
404
405impl core::ops::Rem for c32 {
406    type Output = c32;
407
408    #[inline(always)]
409    fn rem(self, rhs: Self) -> Self::Output {
410        self.to_num_complex().rem(rhs.to_num_complex()).into()
411    }
412}
413
414impl core::ops::Rem<c32conj> for c32 {
415    type Output = c32;
416
417    #[inline(always)]
418    fn rem(self, rhs: c32conj) -> Self::Output {
419        self.rem(rhs.canonicalize())
420    }
421}
422
423impl core::ops::Rem<c32> for c32conj {
424    type Output = c32;
425
426    #[inline(always)]
427    fn rem(self, rhs: c32) -> Self::Output {
428        self.canonicalize().rem(rhs)
429    }
430}
431
432impl core::ops::AddAssign<f32> for c32 {
433    #[inline(always)]
434    fn add_assign(&mut self, rhs: f32) {
435        self.re += rhs;
436    }
437}
438
439impl core::ops::AddAssign for c32 {
440    #[inline(always)]
441    fn add_assign(&mut self, rhs: c32) {
442        self.re += rhs.re;
443        self.im += rhs.im;
444    }
445}
446
447impl core::ops::AddAssign<c32conj> for c32 {
448    #[inline(always)]
449    fn add_assign(&mut self, rhs: c32conj) {
450        self.re += rhs.re;
451        self.im -= rhs.neg_im;
452    }
453}
454
455impl core::ops::SubAssign<f32> for c32 {
456    #[inline(always)]
457    fn sub_assign(&mut self, rhs: f32) {
458        self.re -= rhs;
459    }
460}
461
462impl core::ops::SubAssign for c32 {
463    #[inline(always)]
464    fn sub_assign(&mut self, rhs: c32) {
465        self.re -= rhs.re;
466        self.im -= rhs.im;
467    }
468}
469
470impl core::ops::SubAssign<c32conj> for c32 {
471    #[inline(always)]
472    fn sub_assign(&mut self, rhs: c32conj) {
473        self.re -= rhs.re;
474        self.im += rhs.neg_im;
475    }
476}
477
478impl core::ops::MulAssign<f32> for c32 {
479    #[inline(always)]
480    fn mul_assign(&mut self, rhs: f32) {
481        self.re *= rhs;
482        self.im *= rhs;
483    }
484}
485
486impl core::ops::MulAssign for c32 {
487    #[inline(always)]
488    fn mul_assign(&mut self, rhs: c32) {
489        *self = *self * rhs;
490    }
491}
492
493impl core::ops::MulAssign<c32conj> for c32 {
494    #[inline(always)]
495    fn mul_assign(&mut self, rhs: c32conj) {
496        *self = *self * rhs;
497    }
498}
499
500impl core::ops::DivAssign<f32> for c32 {
501    #[inline(always)]
502    fn div_assign(&mut self, rhs: f32) {
503        self.re /= rhs;
504        self.im /= rhs;
505    }
506}
507
508impl core::ops::DivAssign for c32 {
509    #[inline(always)]
510    fn div_assign(&mut self, rhs: c32) {
511        *self *= rhs.faer_inv();
512    }
513}
514
515impl core::ops::DivAssign<c32conj> for c32 {
516    #[inline(always)]
517    fn div_assign(&mut self, rhs: c32conj) {
518        *self *= rhs.canonicalize().faer_inv();
519    }
520}
521
522impl core::ops::RemAssign<f32> for c32 {
523    #[inline(always)]
524    fn rem_assign(&mut self, rhs: f32) {
525        self.re %= rhs;
526        self.im %= rhs;
527    }
528}
529
530impl core::ops::RemAssign for c32 {
531    #[inline(always)]
532    fn rem_assign(&mut self, rhs: c32) {
533        *self = *self % rhs;
534    }
535}
536
537impl core::ops::RemAssign<c32conj> for c32 {
538    #[inline(always)]
539    fn rem_assign(&mut self, rhs: c32conj) {
540        *self = *self % rhs;
541    }
542}
543
544impl num_traits::Inv for c32 {
545    type Output = c32;
546
547    #[inline(always)]
548    fn inv(self) -> Self::Output {
549        self.faer_inv()
550    }
551}
552
553impl num_traits::Num for c32 {
554    type FromStrRadixErr =
555        num_complex::ParseComplexError<<f32 as num_traits::Num>::FromStrRadixErr>;
556
557    #[inline(always)]
558    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
559        let num_complex = num_complex::Complex32::from_str_radix(str, radix)?;
560        Ok(num_complex.into())
561    }
562}
563
564impl From<c32> for num_complex::Complex32 {
565    #[inline(always)]
566    fn from(value: c32) -> Self {
567        Self {
568            re: value.re,
569            im: value.im,
570        }
571    }
572}
573
574impl From<num_complex::Complex32> for c32 {
575    #[inline(always)]
576    fn from(value: num_complex::Complex32) -> Self {
577        c32 {
578            re: value.re,
579            im: value.im,
580        }
581    }
582}
583
584impl From<f32> for c32 {
585    #[inline(always)]
586    fn from(value: f32) -> Self {
587        Self::new(value, 0.0)
588    }
589}
590
591impl<'a> From<&'a f32> for c32 {
592    #[inline(always)]
593    fn from(value: &'a f32) -> Self {
594        Self::new(*value, 0.0)
595    }
596}
597
598unsafe impl bytemuck::Zeroable for c32 {}
599unsafe impl bytemuck::Pod for c32 {}
600
601impl core::fmt::Debug for c32 {
602    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
603        self.re.fmt(f)?;
604        let im_abs = self.im.faer_abs();
605        if self.im.is_sign_positive() {
606            f.write_str(" + ")?;
607            im_abs.fmt(f)?;
608        } else {
609            f.write_str(" - ")?;
610            im_abs.fmt(f)?;
611        }
612        f.write_str(" * I")
613    }
614}
615
616impl core::fmt::Display for c32 {
617    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
618        <Self as core::fmt::Debug>::fmt(self, f)
619    }
620}
621
622impl ComplexField for c32 {
623    type Real = f32;
624    type Simd = pulp::Arch;
625    type ScalarSimd = NoSimd;
626    type PortableSimd = pulp::Arch;
627
628    #[inline(always)]
629    fn faer_from_f64(value: f64) -> Self {
630        Self {
631            re: value as _,
632            im: 0.0,
633        }
634    }
635
636    #[inline(always)]
637    fn faer_add(self, rhs: Self) -> Self {
638        Self {
639            re: self.re + rhs.re,
640            im: self.im + rhs.im,
641        }
642    }
643
644    #[inline(always)]
645    fn faer_sub(self, rhs: Self) -> Self {
646        Self {
647            re: self.re - rhs.re,
648            im: self.im - rhs.im,
649        }
650    }
651
652    #[inline(always)]
653    fn faer_mul(self, rhs: Self) -> Self {
654        Self {
655            re: self.re * rhs.re - self.im * rhs.im,
656            im: self.re * rhs.im + self.im * rhs.re,
657        }
658    }
659
660    #[inline(always)]
661    fn faer_neg(self) -> Self {
662        Self {
663            re: -self.re,
664            im: -self.im,
665        }
666    }
667
668    #[inline(always)]
669    fn faer_conj(self) -> Self {
670        Self {
671            re: self.re,
672            im: -self.im,
673        }
674    }
675
676    #[inline(always)]
677    fn faer_scale_real(self, rhs: Self::Real) -> Self {
678        Self {
679            re: rhs * self.re,
680            im: rhs * self.im,
681        }
682    }
683
684    #[inline(always)]
685    fn faer_scale_power_of_two(self, rhs: Self::Real) -> Self {
686        Self {
687            re: rhs * self.re,
688            im: rhs * self.im,
689        }
690    }
691
692    #[inline(always)]
693    fn faer_score(self) -> Self::Real {
694        self.faer_abs2()
695    }
696
697    #[inline(always)]
698    fn faer_abs2(self) -> Self::Real {
699        self.re * self.re + self.im * self.im
700    }
701
702    #[inline(always)]
703    fn faer_nan() -> Self {
704        Self {
705            re: Self::Real::NAN,
706            im: Self::Real::NAN,
707        }
708    }
709
710    #[inline(always)]
711    fn faer_from_real(real: Self::Real) -> Self {
712        Self { re: real, im: 0.0 }
713    }
714
715    #[inline(always)]
716    fn faer_real(self) -> Self::Real {
717        self.re
718    }
719
720    #[inline(always)]
721    fn faer_imag(self) -> Self::Real {
722        self.im
723    }
724
725    #[inline(always)]
726    fn faer_zero() -> Self {
727        Self { re: 0.0, im: 0.0 }
728    }
729
730    #[inline(always)]
731    fn faer_one() -> Self {
732        Self { re: 1.0, im: 0.0 }
733    }
734
735    #[inline(always)]
736    fn faer_inv(self) -> Self {
737        self.to_num_complex().faer_inv().into()
738    }
739
740    #[inline(always)]
741    fn faer_sqrt(self) -> Self {
742        self.to_num_complex().faer_sqrt().into()
743    }
744
745    #[inline(always)]
746    fn faer_abs(self) -> Self::Real {
747        self.to_num_complex().faer_abs()
748    }
749
750    #[inline(always)]
751    fn faer_slice_as_simd<S: Simd>(slice: &[Self::Unit]) -> (&[Self::SimdUnit<S>], &[Self::Unit]) {
752        let (head, tail) = S::c32s_as_simd(bytemuck::cast_slice(slice));
753        (bytemuck::cast_slice(head), bytemuck::cast_slice(tail))
754    }
755
756    #[inline(always)]
757    fn faer_slice_as_simd_mut<S: Simd>(
758        slice: &mut [Self::Unit],
759    ) -> (&mut [Self::SimdUnit<S>], &mut [Self::Unit]) {
760        let (head, tail) = S::c32s_as_mut_simd(bytemuck::cast_slice_mut(slice));
761        (
762            bytemuck::cast_slice_mut(head),
763            bytemuck::cast_slice_mut(tail),
764        )
765    }
766
767    #[inline(always)]
768    fn faer_partial_load_last_unit<S: Simd>(simd: S, slice: &[Self::Unit]) -> Self::SimdUnit<S> {
769        simd.c32s_partial_load_last(bytemuck::cast_slice(slice))
770    }
771
772    #[inline(always)]
773    fn faer_partial_store_last_unit<S: Simd>(
774        simd: S,
775        slice: &mut [Self::Unit],
776        values: Self::SimdUnit<S>,
777    ) {
778        simd.c32s_partial_store_last(bytemuck::cast_slice_mut(slice), values)
779    }
780
781    #[inline(always)]
782    fn faer_partial_load_unit<S: Simd>(simd: S, slice: &[Self::Unit]) -> Self::SimdUnit<S> {
783        simd.c32s_partial_load(bytemuck::cast_slice(slice))
784    }
785
786    #[inline(always)]
787    fn faer_partial_store_unit<S: Simd>(
788        simd: S,
789        slice: &mut [Self::Unit],
790        values: Self::SimdUnit<S>,
791    ) {
792        simd.c32s_partial_store(bytemuck::cast_slice_mut(slice), values)
793    }
794
795    #[inline(always)]
796    fn faer_simd_splat_unit<S: Simd>(simd: S, unit: Self::Unit) -> Self::SimdUnit<S> {
797        simd.c32s_splat(pulp::cast(unit))
798    }
799
800    #[inline(always)]
801    fn faer_simd_neg<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> SimdGroupFor<Self, S> {
802        simd.c32s_neg(values)
803    }
804
805    #[inline(always)]
806    fn faer_simd_conj<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> SimdGroupFor<Self, S> {
807        let _ = simd;
808        values
809    }
810
811    #[inline(always)]
812    fn faer_simd_add<S: Simd>(
813        simd: S,
814        lhs: SimdGroupFor<Self, S>,
815        rhs: SimdGroupFor<Self, S>,
816    ) -> SimdGroupFor<Self, S> {
817        simd.c32s_add(lhs, rhs)
818    }
819
820    #[inline(always)]
821    fn faer_simd_sub<S: Simd>(
822        simd: S,
823        lhs: SimdGroupFor<Self, S>,
824        rhs: SimdGroupFor<Self, S>,
825    ) -> SimdGroupFor<Self, S> {
826        simd.c32s_sub(lhs, rhs)
827    }
828
829    #[inline(always)]
830    fn faer_simd_mul<S: Simd>(
831        simd: S,
832        lhs: SimdGroupFor<Self, S>,
833        rhs: SimdGroupFor<Self, S>,
834    ) -> SimdGroupFor<Self, S> {
835        simd.c32s_mul(lhs, rhs)
836    }
837    #[inline(always)]
838    fn faer_simd_scale_real<S: Simd>(
839        simd: S,
840        lhs: SimdGroupFor<Self::Real, S>,
841        rhs: SimdGroupFor<Self, S>,
842    ) -> SimdGroupFor<Self, S> {
843        if coe::is_same::<pulp::Scalar, S>() {
844            let lhs: f32 = bytemuck::cast(lhs);
845            let rhs: num_complex::Complex32 = bytemuck::cast(rhs);
846            bytemuck::cast(lhs * rhs)
847        } else {
848            bytemuck::cast(simd.f32s_mul(lhs, bytemuck::cast(rhs)))
849        }
850    }
851    #[inline(always)]
852    fn faer_simd_conj_mul<S: Simd>(
853        simd: S,
854        lhs: SimdGroupFor<Self, S>,
855        rhs: SimdGroupFor<Self, S>,
856    ) -> SimdGroupFor<Self, S> {
857        simd.c32s_conj_mul(lhs, rhs)
858    }
859
860    #[inline(always)]
861    fn faer_simd_mul_adde<S: Simd>(
862        simd: S,
863        lhs: SimdGroupFor<Self, S>,
864        rhs: SimdGroupFor<Self, S>,
865        acc: SimdGroupFor<Self, S>,
866    ) -> SimdGroupFor<Self, S> {
867        simd.c32s_mul_add_e(lhs, rhs, acc)
868    }
869
870    #[inline(always)]
871    fn faer_simd_conj_mul_adde<S: Simd>(
872        simd: S,
873        lhs: SimdGroupFor<Self, S>,
874        rhs: SimdGroupFor<Self, S>,
875        acc: SimdGroupFor<Self, S>,
876    ) -> SimdGroupFor<Self, S> {
877        simd.c32s_conj_mul_add_e(lhs, rhs, acc)
878    }
879
880    #[inline(always)]
881    fn faer_simd_reduce_add<S: Simd>(simd: S, values: SimdGroupFor<Self, S>) -> Self {
882        pulp::cast(simd.c32s_reduce_sum(values))
883    }
884
885    #[inline(always)]
886    fn faer_simd_abs2_adde<S: Simd>(
887        simd: S,
888        values: SimdGroupFor<Self, S>,
889        acc: SimdGroupFor<Self::Real, S>,
890    ) -> SimdGroupFor<Self::Real, S> {
891        let _ = (simd, values, acc);
892        unimplemented!("c32/c64 require special treatment when converted to their real counterparts in simd kernels");
893    }
894    #[inline(always)]
895    fn faer_simd_abs2<S: Simd>(
896        simd: S,
897        values: SimdGroupFor<Self, S>,
898    ) -> SimdGroupFor<Self::Real, S> {
899        let _ = (simd, values);
900        unimplemented!("c32/c64 require special treatment when converted to their real counterparts in simd kernels");
901    }
902    #[inline(always)]
903    fn faer_simd_score<S: Simd>(
904        simd: S,
905        values: SimdGroupFor<Self, S>,
906    ) -> SimdGroupFor<Self::Real, S> {
907        let _ = (simd, values);
908        unimplemented!("c32/c64 require special treatment when converted to their real counterparts in simd kernels");
909    }
910
911    #[inline(always)]
912    fn faer_simd_scalar_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
913        cast(simd.c32_scalar_mul(cast(lhs), cast(rhs)))
914    }
915    #[inline(always)]
916    fn faer_simd_scalar_conj_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
917        cast(simd.c32_scalar_conj_mul(cast(lhs), cast(rhs)))
918    }
919    #[inline(always)]
920    fn faer_simd_scalar_mul_adde<S: Simd>(simd: S, lhs: Self, rhs: Self, acc: Self) -> Self {
921        cast(simd.c32_scalar_mul_add_e(cast(lhs), cast(rhs), cast(acc)))
922    }
923    #[inline(always)]
924    fn faer_simd_scalar_conj_mul_adde<S: Simd>(simd: S, lhs: Self, rhs: Self, acc: Self) -> Self {
925        cast(simd.c32_scalar_conj_mul_add_e(cast(lhs), cast(rhs), cast(acc)))
926    }
927
928    #[inline(always)]
929    fn faer_align_offset<S: Simd>(
930        simd: S,
931        ptr: *const UnitFor<Self>,
932        len: usize,
933    ) -> pulp::Offset<SimdMaskFor<Self, S>> {
934        simd.c32s_align_offset(ptr as _, len)
935    }
936
937    #[inline(always)]
938    fn faer_slice_as_aligned_simd<S: Simd>(
939        simd: S,
940        slice: &[UnitFor<Self>],
941        offset: pulp::Offset<SimdMaskFor<Self, S>>,
942    ) -> (
943        Self::PrefixUnit<'_, S>,
944        &[SimdUnitFor<Self, S>],
945        Self::SuffixUnit<'_, S>,
946    ) {
947        simd.c32s_as_aligned_simd(bytemuck::cast_slice(slice), offset)
948    }
949
950    #[inline(always)]
951    fn faer_slice_as_aligned_simd_mut<S: Simd>(
952        simd: S,
953        slice: &mut [UnitFor<Self>],
954        offset: pulp::Offset<SimdMaskFor<Self, S>>,
955    ) -> (
956        Self::PrefixMutUnit<'_, S>,
957        &mut [SimdUnitFor<Self, S>],
958        Self::SuffixMutUnit<'_, S>,
959    ) {
960        simd.c32s_as_aligned_mut_simd(bytemuck::cast_slice_mut(slice), offset)
961    }
962
963    #[inline(always)]
964    fn faer_simd_rotate_left<S: Simd>(
965        simd: S,
966        values: SimdGroupFor<Self, S>,
967        amount: usize,
968    ) -> SimdGroupFor<Self, S> {
969        simd.c32s_rotate_left(values, amount)
970    }
971}
972
973unsafe impl Entity for c32 {
974    type Unit = Self;
975    type Index = u32;
976    type SimdUnit<S: Simd> = S::c32s;
977    type SimdMask<S: Simd> = S::m32s;
978    type SimdIndex<S: Simd> = S::u32s;
979    type Group = IdentityGroup;
980    type Iter<I: Iterator> = I;
981
982    type PrefixUnit<'a, S: Simd> = pulp::Prefix<'a, num_complex::Complex32, S, S::m32s>;
983    type SuffixUnit<'a, S: Simd> = pulp::Suffix<'a, num_complex::Complex32, S, S::m32s>;
984    type PrefixMutUnit<'a, S: Simd> = pulp::PrefixMut<'a, num_complex::Complex32, S, S::m32s>;
985    type SuffixMutUnit<'a, S: Simd> = pulp::SuffixMut<'a, num_complex::Complex32, S, S::m32s>;
986
987    const N_COMPONENTS: usize = 1;
988    const UNIT: GroupCopyFor<Self, ()> = ();
989
990    #[inline(always)]
991    fn faer_first<T>(group: GroupFor<Self, T>) -> T {
992        group
993    }
994
995    #[inline(always)]
996    fn faer_from_units(group: GroupFor<Self, Self::Unit>) -> Self {
997        group
998    }
999
1000    #[inline(always)]
1001    fn faer_into_units(self) -> GroupFor<Self, Self::Unit> {
1002        self
1003    }
1004
1005    #[inline(always)]
1006    fn faer_as_ref<T>(group: &GroupFor<Self, T>) -> GroupFor<Self, &T> {
1007        group
1008    }
1009
1010    #[inline(always)]
1011    fn faer_as_mut<T>(group: &mut GroupFor<Self, T>) -> GroupFor<Self, &mut T> {
1012        group
1013    }
1014
1015    #[inline(always)]
1016    fn faer_as_ptr<T>(group: *mut GroupFor<Self, T>) -> GroupFor<Self, *mut T> {
1017        group
1018    }
1019
1020    #[inline(always)]
1021    fn faer_map_impl<T, U>(
1022        group: GroupFor<Self, T>,
1023        f: &mut impl FnMut(T) -> U,
1024    ) -> GroupFor<Self, U> {
1025        (*f)(group)
1026    }
1027
1028    #[inline(always)]
1029    fn faer_map_with_context<Ctx, T, U>(
1030        ctx: Ctx,
1031        group: GroupFor<Self, T>,
1032        f: &mut impl FnMut(Ctx, T) -> (Ctx, U),
1033    ) -> (Ctx, GroupFor<Self, U>) {
1034        (*f)(ctx, group)
1035    }
1036
1037    #[inline(always)]
1038    fn faer_zip<T, U>(
1039        first: GroupFor<Self, T>,
1040        second: GroupFor<Self, U>,
1041    ) -> GroupFor<Self, (T, U)> {
1042        (first, second)
1043    }
1044    #[inline(always)]
1045    fn faer_unzip<T, U>(zipped: GroupFor<Self, (T, U)>) -> (GroupFor<Self, T>, GroupFor<Self, U>) {
1046        zipped
1047    }
1048
1049    #[inline(always)]
1050    fn faer_into_iter<I: IntoIterator>(iter: GroupFor<Self, I>) -> Self::Iter<I::IntoIter> {
1051        iter.into_iter()
1052    }
1053}
1054
1055unsafe impl Conjugate for c32 {
1056    type Conj = c32conj;
1057    type Canonical = c32;
1058
1059    #[inline(always)]
1060    fn canonicalize(self) -> Self::Canonical {
1061        self
1062    }
1063}