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