1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
65 ComplexScalar, Constants, FpScalar, MulAddRef, RealScalar,
66 core::{
67 errors::{
68 ErrorsRawRealToInteger, ErrorsValidationRawComplex, ErrorsValidationRawReal,
69 RawRealConversionError, capture_backtrace,
70 },
71 policies::validate_complex_from_parts,
72 traits::{
73 RawKernel,
74 raw::{RawScalarValidate, TryConvertFromRawReal},
75 validation::sealed::NativeReal,
76 },
77 },
78 functions::{
79 Clamp, Classify, ExpM1, Hypot, Ln1p, Rounding, Sign, TotalCmp,
80 complex::{
81 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
82 ComplexScalarSetParts,
83 },
84 },
85 kernels::{
86 PrecisionBits, RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow,
87 RawScalarTrait, RawScalarTrigonometric,
88 },
89 scalar_kind,
90};
91use az::CheckedAs;
92use duplicate::duplicate_item;
93use num::{Complex, Zero};
94use num_traits::{Float, FloatConst, MulAdd, MulAddAssign};
95use std::{
96 cmp::Ordering,
97 hash::{Hash, Hasher},
98 num::FpCategory,
99};
100use try_create::IntoInner;
101
102#[derive(Debug, Clone, PartialEq, PartialOrd)]
112pub struct Native<T: NativeReal> {
113 _marker: std::marker::PhantomData<T>,
114}
115
116impl<T: NativeReal> RawKernel for Native<T>
117where
118 T: RawRealTrait<RawComplex = Complex<T>>,
119 Complex<T>: RawComplexTrait<RawReal = T>,
120{
121 type RawReal = T;
123
124 type RawComplex = Complex<T>;
126}
127
128pub type Native64 = Native<f64>;
129pub type Native32 = Native<f32>;
130
131#[duplicate_item(
139 T;
140 [f64];
141 [f32];
142)]
143impl FpScalar for T {
144 type Kind = scalar_kind::Real;
145
146 type RealType = T;
148
149 fn as_raw_ref(&self) -> &Self::InnerType {
151 self
152 }
153}
154
155impl<T> FpScalar for Complex<T>
160where
161 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
162 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar,
163{
164 type Kind = scalar_kind::Complex;
165
166 type RealType = T;
168
169 fn as_raw_ref(&self) -> &Self::InnerType {
171 self
172 }
173}
174impl<T: NativeReal> Sign for T {
178 #[inline(always)]
180 fn kernel_copysign(self, sign: &Self) -> Self {
181 self.copysign(*sign)
182 }
183
184 #[inline(always)]
186 fn kernel_is_sign_negative(&self) -> bool {
187 self.is_sign_negative()
188 }
189
190 #[inline(always)]
192 fn kernel_is_sign_positive(&self) -> bool {
193 self.is_sign_positive()
194 }
195
196 #[inline(always)]
203 fn kernel_signum(self) -> Self {
204 self.signum()
205 }
206}
207
208impl<T: NativeReal> Rounding for T {
209 #[inline(always)]
211 fn kernel_ceil(self) -> Self {
212 self.ceil()
213 }
214
215 #[inline(always)]
217 fn kernel_floor(self) -> Self {
218 self.floor()
219 }
220
221 #[inline(always)]
223 fn kernel_fract(self) -> Self {
224 self.fract()
225 }
226
227 #[inline(always)]
229 fn kernel_round(self) -> Self {
230 self.round()
231 }
232
233 #[inline(always)]
252 fn kernel_round_ties_even(self) -> Self {
253 self.round_ties_even_native_real()
254 }
255
256 #[inline(always)]
271 fn kernel_trunc(self) -> Self {
272 self.trunc()
273 }
274}
275
276impl<T: NativeReal> Constants for T {
277 #[inline(always)]
283 fn epsilon() -> Self {
284 <T as Float>::epsilon()
285 }
286
287 #[inline(always)]
289 fn negative_one() -> Self {
290 T::raw_negative_one(T::MANTISSA_DIGITS)
291 }
292
293 #[inline(always)]
295 fn one_div_2() -> Self {
296 T::raw_one_div_2(T::MANTISSA_DIGITS)
297 }
298
299 #[inline(always)]
301 fn two() -> Self {
302 T::raw_two(T::MANTISSA_DIGITS)
303 }
304
305 #[inline(always)]
307 fn max_finite() -> Self {
308 <T as Float>::max_value()
309 }
310
311 #[inline(always)]
313 fn min_finite() -> Self {
314 <T as Float>::min_value()
315 }
316
317 #[inline(always)]
319 fn pi() -> Self {
320 <T as FloatConst>::PI()
321 }
322
323 #[inline(always)]
325 fn two_pi() -> Self {
326 <T as FloatConst>::TAU()
327 }
328
329 #[inline(always)]
331 fn pi_div_2() -> Self {
332 <T as FloatConst>::FRAC_PI_2()
333 }
334
335 #[inline(always)]
337 fn ln_2() -> Self {
338 <T as FloatConst>::LN_2()
339 }
340
341 #[inline(always)]
343 fn ln_10() -> Self {
344 <T as FloatConst>::LN_10()
345 }
346
347 #[inline(always)]
349 fn log10_2() -> Self {
350 <T as FloatConst>::LOG10_2()
351 }
352
353 #[inline(always)]
355 fn log2_10() -> Self {
356 <T as FloatConst>::LOG2_10()
357 }
358
359 #[inline(always)]
361 fn log2_e() -> Self {
362 <T as FloatConst>::LOG2_E()
363 }
364
365 #[inline(always)]
367 fn log10_e() -> Self {
368 <T as FloatConst>::LOG10_E()
369 }
370
371 #[inline(always)]
373 fn e() -> Self {
374 <T as FloatConst>::E()
375 }
376}
377
378impl<T: NativeReal> Clamp for T {
379 #[inline(always)]
397 fn clamp_ref(self, min: &Self, max: &Self) -> Self {
398 <T as Float>::clamp(self, *min, *max)
399 }
400}
401
402impl<T: NativeReal> Classify for T {
403 #[inline(always)]
416 fn classify(&self) -> FpCategory {
417 <T as Float>::classify(*self)
418 }
419}
420
421impl<T: NativeReal> ExpM1 for T {
422 #[inline(always)]
424 fn exp_m1(self) -> Self {
425 <T as Float>::exp_m1(self)
426 }
427}
428
429impl<T: NativeReal> Hypot for T {
430 #[inline(always)]
433 fn hypot(self, other: &Self) -> Self {
434 <T as Float>::hypot(self, *other)
435 }
436}
437
438impl<T: NativeReal> Ln1p for T {
439 #[inline(always)]
441 fn ln_1p(self) -> Self {
442 <T as Float>::ln_1p(self)
443 }
444}
445
446impl<T: NativeReal> TotalCmp for T {
447 #[inline(always)]
448 fn total_cmp(&self, other: &Self) -> Ordering {
449 self.raw_total_cmp(other)
450 }
451}
452
453impl<T: NativeReal> PrecisionBits for T {
454 #[inline(always)]
455 fn precision_bits(&self) -> u32 {
456 T::MANTISSA_DIGITS
457 }
458}
459
460#[duplicate_item(
461 T;
462 [f64];
463 [f32];
464)]
465impl RealScalar for T {
466 type RawReal = T;
467
468 #[inline(always)]
471 fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
472 self.mul_add_assign(*mul, add_mul1 * add_mul2);
473 }
474
475 #[inline(always)]
478 fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
479 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
480 }
481
482 #[inline(always)]
483 fn try_new_from_raw_real<RawRealIn>(
484 value: RawRealIn,
485 ) -> Result<Self, RawRealConversionError<RawRealIn, Self::RawReal>>
486 where
487 RawRealIn: RawRealTrait,
488 Self::RawReal: TryConvertFromRawReal<RawRealIn>,
489 {
490 value.try_convert::<Self::RawReal>(T::MANTISSA_DIGITS)
491 }
492}
493
494impl<T> ComplexScalarConstructors for Complex<T>
495where
496 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
497 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
498{
499 type RawComplex = Complex<T>;
500
501 fn try_new_complex(
502 real_part: T,
503 imag_part: T,
504 ) -> Result<Self, ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>> {
505 validate_complex_from_parts(&real_part, &imag_part, T::validate_raw_scalar_ref)
506 .map(|_| Complex::new(real_part, imag_part))
507 }
508}
509
510impl<T> ComplexScalarGetParts for Complex<T>
512where
513 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
514 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
515{
516 #[inline(always)]
518 fn real_part(&self) -> T {
519 self.re
520 }
521
522 #[inline(always)]
524 fn imag_part(&self) -> T {
525 self.im
526 }
527
528 #[inline(always)]
530 fn raw_real_part(&self) -> &T {
531 &self.re
532 }
533
534 #[inline(always)]
536 fn raw_imag_part(&self) -> &T {
537 &self.im
538 }
539}
540
541impl<T> ComplexScalarSetParts for Complex<T>
542where
543 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
544 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
545{
546 #[inline(always)]
552 fn set_real_part(&mut self, real_part: T) {
553 debug_assert!(
554 real_part.is_finite(),
555 "The real part is not finite (i.e. is infinite or NaN)."
556 );
557 self.re = real_part;
558 }
559
560 #[inline(always)]
566 fn set_imaginary_part(&mut self, imag_part: T) {
567 debug_assert!(
568 imag_part.is_finite(),
569 "The imaginary part is not finite (i.e. is infinite or NaN)."
570 );
571 self.im = imag_part;
572 }
573}
574
575impl<T> ComplexScalarMutateParts for Complex<T>
576where
577 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
578 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
579{
580 #[inline(always)]
586 fn add_to_real_part(&mut self, c: &T) {
587 self.re += c;
588
589 debug_assert!(
590 self.re.is_finite(),
591 "The real part is not finite (i.e. is infinite or NaN)."
592 );
593 }
594
595 #[inline(always)]
601 fn add_to_imaginary_part(&mut self, c: &T) {
602 self.im += c;
603
604 debug_assert!(
605 self.im.is_finite(),
606 "The imaginary part is not finite (i.e. is infinite or NaN)."
607 );
608 }
609
610 #[inline(always)]
616 fn multiply_real_part(&mut self, c: &T) {
617 self.re *= c;
618
619 debug_assert!(
620 self.re.is_finite(),
621 "The real part is not finite (i.e. is infinite or NaN)."
622 );
623 }
624
625 #[inline(always)]
631 fn multiply_imaginary_part(&mut self, c: &T) {
632 self.im *= c;
633
634 debug_assert!(
635 self.im.is_finite(),
636 "The imaginary part is not finite (i.e. is infinite or NaN)."
637 );
638 }
639}
640
641impl<T> ComplexScalar for Complex<T>
642where
643 Self: RawComplexTrait<RawReal = T> + IntoInner<InnerType = Self>,
644 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
645{
646 fn into_parts(self) -> (Self::RealType, Self::RealType) {
647 (self.re, self.im)
648 }
649}
650
651impl<T> MulAddRef for T
655where
656 T: MulAdd<Output = T> + Copy,
657{
658 #[inline(always)]
662 fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
663 Self::mul_add(self, *b, *c)
664 }
665}
666impl<T: NativeReal> RawScalarTrigonometric for T {
673 #[duplicate_item(
674 unchecked_method method;
675 [unchecked_sin] [sin];
676 [unchecked_asin] [asin];
677 [unchecked_cos] [cos];
678 [unchecked_acos] [acos];
679 [unchecked_tan] [tan];
680 [unchecked_atan] [atan];
681 )]
682 #[inline(always)]
683 fn unchecked_method(self) -> Self {
684 T::method(self)
685 }
686}
687
688impl<T: NativeReal> RawScalarTrigonometric for Complex<T> {
689 #[duplicate_item(
690 unchecked_method method;
691 [unchecked_sin] [sin];
692 [unchecked_asin] [asin];
693 [unchecked_cos] [cos];
694 [unchecked_acos] [acos];
695 [unchecked_tan] [tan];
696 [unchecked_atan] [atan];
697 )]
698 #[inline(always)]
699 fn unchecked_method(self) -> Self {
700 Complex::<T>::method(self)
701 }
702}
703
704impl<T: NativeReal> RawScalarHyperbolic for T {
705 #[duplicate_item(
706 unchecked_method method;
707 [unchecked_sinh] [sinh];
708 [unchecked_asinh] [asinh];
709 [unchecked_cosh] [cosh];
710 [unchecked_acosh] [acosh];
711 [unchecked_tanh] [tanh];
712 [unchecked_atanh] [atanh];
713 )]
714 #[inline(always)]
715 fn unchecked_method(self) -> Self {
716 T::method(self)
717 }
718}
719
720impl<T: NativeReal> RawScalarHyperbolic for Complex<T> {
721 #[duplicate_item(
722 unchecked_method method;
723 [unchecked_sinh] [sinh];
724 [unchecked_asinh] [asinh];
725 [unchecked_cosh] [cosh];
726 [unchecked_acosh] [acosh];
727 [unchecked_tanh] [tanh];
728 [unchecked_atanh] [atanh];
729 )]
730 #[inline(always)]
731 fn unchecked_method(self) -> Self {
732 Complex::<T>::method(self)
733 }
734}
735
736impl<T: NativeReal> RawScalarPow for T {
737 #[duplicate_item(
738 unchecked_method exponent_type;
739 [unchecked_pow_exponent_i8] [i8];
740 [unchecked_pow_exponent_i16] [i16];
741 [unchecked_pow_exponent_u8] [u8];
742 [unchecked_pow_exponent_u16] [u16];
743 )]
744 #[inline(always)]
745 fn unchecked_method(self, exponent: &exponent_type) -> T {
746 T::powi(self, (*exponent).into())
747 }
748
749 #[inline(always)]
750 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
751 T::powi(self, *exponent)
752 }
753
754 #[duplicate_item(
755 unchecked_method exponent_type;
756 [unchecked_pow_exponent_i64] [i64];
757 [unchecked_pow_exponent_i128] [i128];
758 [unchecked_pow_exponent_isize] [isize];
759 [unchecked_pow_exponent_u32] [u32];
760 [unchecked_pow_exponent_u64] [u64];
761 [unchecked_pow_exponent_u128] [u128];
762 [unchecked_pow_exponent_usize] [usize];
763 )]
764 #[inline(always)]
765 fn unchecked_method(self, exponent: &exponent_type) -> T {
766 T::powi(
767 self,
768 (*exponent)
769 .try_into()
770 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
771 )
772 }
773}
774
775impl<T: NativeReal> RawScalarValidate for T {
776 type ValidationError = ErrorsValidationRawReal<T>;
777
778 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
779 match self.classify() {
780 FpCategory::Nan => Err(ErrorsValidationRawReal::IsNaN {
781 value: *self,
782 backtrace: capture_backtrace(),
783 }),
784 FpCategory::Infinite => {
785 if self.is_sign_positive() {
786 Err(ErrorsValidationRawReal::IsPosInfinity {
787 backtrace: capture_backtrace(),
788 })
789 } else {
790 Err(ErrorsValidationRawReal::IsNegInfinity {
791 backtrace: capture_backtrace(),
792 })
793 }
794 }
795 FpCategory::Subnormal => Err(ErrorsValidationRawReal::IsSubnormal {
796 value: *self,
797 backtrace: capture_backtrace(),
798 }),
799 FpCategory::Normal | FpCategory::Zero => Ok(()),
800 }
801 }
802}
803
804#[inline(always)]
805fn debug_assert_if_invalid_precision<T: NativeReal>(precision: u32) {
806 debug_assert_eq!(
807 precision,
808 T::MANTISSA_DIGITS,
809 "Precision {precision} must be equal to the mantissa digits for type {} (mantissa digits = {}).",
810 std::any::type_name::<T>(),
811 T::MANTISSA_DIGITS
812 );
813}
814
815impl<T: NativeReal> RawScalarTrait for T {
816 #[inline(always)]
817 fn raw_zero(_precision: u32) -> T {
818 debug_assert_if_invalid_precision::<T>(_precision);
819 T::zero()
820 }
821
822 #[inline(always)]
823 fn is_zero(&self) -> bool {
824 <Self as Zero>::is_zero(self)
825 }
826 #[inline(always)]
827 fn raw_one(_precision: u32) -> T {
828 debug_assert_if_invalid_precision::<T>(_precision);
829 T::one()
830 }
831
832 #[duplicate_item(
833 unchecked_method method;
834 [unchecked_reciprocal] [recip];
835 [unchecked_exp] [exp];
836 [unchecked_sqrt] [sqrt];
837 [unchecked_ln] [ln];
838 [unchecked_log2] [log2];
839 [unchecked_log10] [log10];
840 )]
841 #[inline(always)]
842 fn unchecked_method(self) -> T {
843 <T as Float>::method(self)
844 }
845
846 #[inline(always)]
850 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
851 Float::mul_add(self, *b, *c)
852 }
853
854 #[inline(always)]
855 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
856 debug_assert!(
857 self.is_finite(),
858 concat!(
859 "Hashing a non-finite ",
860 stringify!(T),
861 " floating-point value (i.e., NaN or Infinity) may lead to inconsistent results."
862 )
863 );
864 let zero = T::zero();
865 if self == &zero {
866 zero.to_bits_native_real().hash(state);
868 } else {
869 self.to_bits_native_real().hash(state);
870 }
871 }
872}
873
874#[duplicate_item(
875 T;
876 [f64];
877 [f32];
878)]
879impl RawRealTrait for T {
880 type RawComplex = Complex<T>;
881
882 #[inline(always)]
883 fn unchecked_abs(self) -> Self {
884 <T as Float>::abs(self)
885 }
886
887 #[inline(always)]
888 fn unchecked_atan2(self, denominator: &Self) -> Self {
889 <T as Float>::atan2(self, *denominator)
890 }
891
892 #[inline(always)]
893 fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
894 <T as Float>::powf(self, *exponent)
895 }
896
897 #[inline(always)]
898 fn unchecked_hypot(self, other: &Self) -> Self {
899 <T as Float>::hypot(self, *other)
900 }
901
902 #[inline(always)]
903 fn unchecked_ln_1p(self) -> Self {
904 <T as Float>::ln_1p(self)
905 }
906
907 #[inline(always)]
908 fn unchecked_exp_m1(self) -> Self {
909 <T as Float>::exp_m1(self)
910 }
911
912 #[inline(always)]
915 fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
916 self.mul_add_assign(*mul, add_mul1 * add_mul2);
917 }
918
919 #[inline(always)]
922 fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
923 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
924 }
925
926 #[inline(always)]
927 fn raw_total_cmp(&self, other: &Self) -> Ordering {
928 T::total_cmp(self, other)
929 }
930
931 #[inline(always)]
933 fn raw_clamp(self, min: &Self, max: &Self) -> Self {
934 <T as Float>::clamp(self, *min, *max)
935 }
936
937 #[inline(always)]
938 fn raw_classify(&self) -> FpCategory {
939 <T as Float>::classify(*self)
940 }
941
942 #[inline(always)]
943 fn raw_two(_precision: u32) -> Self {
944 debug_assert_if_invalid_precision::<T>(_precision);
945 2.
946 }
947
948 #[inline(always)]
949 fn raw_one_div_2(_precision: u32) -> Self {
950 debug_assert_if_invalid_precision::<T>(_precision);
951 0.5
952 }
953
954 #[inline(always)]
955 fn raw_pi(_precision: u32) -> Self {
956 debug_assert_if_invalid_precision::<T>(_precision);
957 <T as FloatConst>::PI()
958 }
959
960 #[inline(always)]
961 fn raw_two_pi(_precision: u32) -> Self {
962 debug_assert_if_invalid_precision::<T>(_precision);
963 <T as FloatConst>::TAU()
964 }
965
966 #[inline(always)]
967 fn raw_pi_div_2(_precision: u32) -> Self {
968 debug_assert_if_invalid_precision::<T>(_precision);
969 <T as FloatConst>::FRAC_PI_2()
970 }
971
972 #[inline(always)]
973 fn raw_max_finite(_precision: u32) -> Self {
974 debug_assert_if_invalid_precision::<T>(_precision);
975 <T as Float>::max_value()
976 }
977
978 #[inline(always)]
979 fn raw_min_finite(_precision: u32) -> Self {
980 debug_assert_if_invalid_precision::<T>(_precision);
981 <T as Float>::min_value()
982 }
983
984 #[inline(always)]
985 fn raw_epsilon(_precision: u32) -> Self {
986 debug_assert_if_invalid_precision::<T>(_precision);
987 <T as Float>::epsilon()
988 }
989
990 #[inline(always)]
991 fn raw_ln_2(_precision: u32) -> Self {
992 debug_assert_if_invalid_precision::<T>(_precision);
993 <T as FloatConst>::LN_2()
994 }
995
996 #[inline(always)]
997 fn raw_ln_10(_precision: u32) -> Self {
998 debug_assert_if_invalid_precision::<T>(_precision);
999 <T as FloatConst>::LN_10()
1000 }
1001
1002 #[inline(always)]
1003 fn raw_log10_2(_precision: u32) -> Self {
1004 debug_assert_if_invalid_precision::<T>(_precision);
1005 <T as FloatConst>::LOG10_2()
1006 }
1007
1008 #[inline(always)]
1009 fn raw_log2_10(_precision: u32) -> Self {
1010 debug_assert_if_invalid_precision::<T>(_precision);
1011 <T as FloatConst>::LOG2_10()
1012 }
1013
1014 #[inline(always)]
1015 fn raw_log2_e(_precision: u32) -> Self {
1016 debug_assert_if_invalid_precision::<T>(_precision);
1017 <T as FloatConst>::LOG2_E()
1018 }
1019
1020 #[inline(always)]
1021 fn raw_log10_e(_precision: u32) -> Self {
1022 debug_assert_if_invalid_precision::<T>(_precision);
1023 <T as FloatConst>::LOG10_E()
1024 }
1025
1026 #[inline(always)]
1027 fn raw_e(_precision: u32) -> Self {
1028 debug_assert_if_invalid_precision::<T>(_precision);
1029 <T as FloatConst>::E()
1030 }
1031
1032 #[inline(always)]
1033 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<T, usize>> {
1034 if !self.is_finite() {
1035 return Err(ErrorsRawRealToInteger::NotFinite {
1036 value: self,
1037 backtrace: capture_backtrace(),
1038 });
1039 }
1040
1041 match self.checked_as::<usize>() {
1042 Some(value) => Ok(value),
1043 None => Err(ErrorsRawRealToInteger::OutOfRange {
1044 value: self,
1045 min: usize::MIN,
1046 max: usize::MAX,
1047 backtrace: capture_backtrace(),
1048 }),
1049 }
1050 }
1051}
1052
1053impl<T: NativeReal> RawScalarPow for Complex<T> {
1054 #[duplicate_item(
1055 unchecked_method exponent_type;
1056 [unchecked_pow_exponent_i8] [i8];
1057 [unchecked_pow_exponent_i16] [i16];
1058 )]
1059 #[inline(always)]
1060 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1061 Complex::<T>::powi(&self, (*exponent).into())
1062 }
1063
1064 #[inline(always)]
1065 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
1066 Complex::<T>::powi(&self, *exponent)
1067 }
1068
1069 #[duplicate_item(
1070 unchecked_method exponent_type;
1071 [unchecked_pow_exponent_i64] [i64];
1072 [unchecked_pow_exponent_i128] [i128];
1073 [unchecked_pow_exponent_isize] [isize];
1074 )]
1075 #[inline(always)]
1076 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1077 Complex::<T>::powi(
1078 &self,
1079 (*exponent)
1080 .try_into()
1081 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
1082 )
1083 }
1084
1085 #[duplicate_item(
1086 unchecked_method exponent_type;
1087 [unchecked_pow_exponent_u8] [u8];
1088 [unchecked_pow_exponent_u16] [u16];
1089 )]
1090 #[inline(always)]
1091 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1092 Complex::<T>::powu(&self, (*exponent).into())
1093 }
1094
1095 #[inline(always)]
1096 fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
1097 Complex::<T>::powu(&self, *exponent)
1098 }
1099
1100 #[duplicate_item(
1101 unchecked_method exponent_type;
1102 [unchecked_pow_exponent_u64] [u64];
1103 [unchecked_pow_exponent_u128] [u128];
1104 [unchecked_pow_exponent_usize] [usize];
1105 )]
1106 #[inline(always)]
1107 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1108 Complex::<T>::powu(
1109 &self,
1110 (*exponent)
1111 .try_into()
1112 .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
1113 )
1114 }
1115}
1116
1117impl<T: NativeReal> RawScalarValidate for Complex<T> {
1118 type ValidationError = ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>;
1119
1120 #[inline(always)]
1121 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
1122 validate_complex_from_parts(&self.re, &self.im, T::validate_raw_scalar_ref)
1123 }
1124}
1125
1126impl<T: NativeReal> RawScalarTrait for Complex<T> {
1127 #[inline(always)]
1128 fn raw_zero(_precision: u32) -> Self {
1129 debug_assert_if_invalid_precision::<T>(_precision);
1130 Complex::new(T::zero(), T::zero())
1131 }
1132
1133 #[inline(always)]
1134 fn is_zero(&self) -> bool {
1135 <Self as Zero>::is_zero(self)
1136 }
1137
1138 #[inline(always)]
1139 fn raw_one(_precision: u32) -> Self {
1140 debug_assert_if_invalid_precision::<T>(_precision);
1141 Complex::new(T::one(), T::zero())
1142 }
1143
1144 #[duplicate_item(
1145 unchecked_method method;
1146 [unchecked_exp] [exp];
1147 [unchecked_sqrt] [sqrt];
1148 [unchecked_ln] [ln];
1149 [unchecked_log10] [log10];
1150 )]
1151 #[inline(always)]
1152 fn unchecked_method(self) -> Self {
1153 Complex::<T>::method(self)
1154 }
1155
1156 #[inline(always)]
1157 fn unchecked_reciprocal(self) -> Self {
1158 Complex::<T>::inv(&self)
1159 }
1160
1161 #[inline(always)]
1162 fn unchecked_log2(self) -> Self {
1163 Complex::<T>::ln(self) / <T as FloatConst>::LN_2()
1164 }
1165
1166 #[inline(always)]
1170 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
1171 Complex::<T>::mul_add(self, *b, *c)
1172 }
1173
1174 #[inline(always)]
1175 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
1176 self.re.compute_hash_raw_scalar(state);
1177 self.im.compute_hash_raw_scalar(state);
1178 }
1179}
1180
1181impl<T> RawComplexTrait for Complex<T>
1182where
1183 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RawRealTrait<RawComplex = Self>,
1185{
1186 type RawReal = T;
1187
1188 fn new_unchecked_raw_complex(real: T, imag: T) -> Self {
1189 Complex::<T>::new(real, imag)
1190 }
1191
1192 fn mut_raw_real_part(&mut self) -> &mut T {
1194 &mut self.re
1195 }
1196
1197 fn mut_raw_imag_part(&mut self) -> &mut T {
1199 &mut self.im
1200 }
1201
1202 #[inline(always)]
1203 fn unchecked_abs(self) -> T {
1204 Complex::<T>::norm(self)
1205 }
1206
1207 #[inline(always)]
1208 fn raw_real_part(&self) -> &T {
1209 &self.re
1210 }
1211
1212 #[inline(always)]
1213 fn raw_imag_part(&self) -> &T {
1214 &self.im
1215 }
1216
1217 #[inline(always)]
1218 fn unchecked_arg(self) -> T {
1219 Complex::<T>::arg(self)
1220 }
1221
1222 #[inline(always)]
1223 fn unchecked_pow_exponent_real(self, exponent: &T) -> Self {
1224 Complex::<T>::powf(self, *exponent)
1225 }
1226}
1227
1228#[cfg(test)]
1229mod tests {
1230 use crate::{
1231 core::errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal},
1232 functions::TotalCmp,
1233 };
1234 use std::assert_matches;
1235
1236 mod real {
1237 use super::*;
1238 use crate::Constants;
1239
1240 #[test]
1241 fn test_constants() {
1242 assert_eq!(<f64 as Constants>::epsilon(), f64::EPSILON);
1243 assert_eq!(<f64 as Constants>::negative_one(), -1.0);
1244 assert_eq!(<f64 as Constants>::one_div_2(), 0.5);
1245 assert_eq!(<f64 as Constants>::two(), 2.0);
1246 assert_eq!(<f64 as Constants>::max_finite(), f64::MAX);
1247 assert_eq!(<f64 as Constants>::min_finite(), f64::MIN);
1248 assert_eq!(<f64 as Constants>::pi(), std::f64::consts::PI);
1249 assert_eq!(<f64 as Constants>::two_pi(), std::f64::consts::PI * 2.0);
1250 assert_eq!(<f64 as Constants>::pi_div_2(), std::f64::consts::FRAC_PI_2);
1251 assert_eq!(<f64 as Constants>::ln_2(), std::f64::consts::LN_2);
1252 assert_eq!(<f64 as Constants>::ln_10(), std::f64::consts::LN_10);
1253 assert_eq!(<f64 as Constants>::log10_2(), std::f64::consts::LOG10_2);
1254 assert_eq!(<f64 as Constants>::log2_10(), std::f64::consts::LOG2_10);
1255 assert_eq!(<f64 as Constants>::log2_e(), std::f64::consts::LOG2_E);
1256 assert_eq!(<f64 as Constants>::log10_e(), std::f64::consts::LOG10_E);
1257 assert_eq!(<f64 as Constants>::e(), std::f64::consts::E);
1258 }
1259
1260 #[test]
1261 #[allow(clippy::op_ref)]
1262 fn multiply_ref() {
1263 let a = 2.0f64;
1264 let b = 3.0f64;
1265 let result = a * &b;
1266 assert_eq!(result, 6.0);
1267 }
1268
1269 #[test]
1270 fn total_cmp() {
1271 let a = 2.0f64;
1272 let b = 3.0f64;
1273 assert_eq!(
1274 <f64 as TotalCmp>::total_cmp(&a, &b),
1275 std::cmp::Ordering::Less
1276 );
1277 assert_eq!(
1278 <f64 as TotalCmp>::total_cmp(&b, &a),
1279 std::cmp::Ordering::Greater
1280 );
1281 assert_eq!(
1282 <f64 as TotalCmp>::total_cmp(&a, &a),
1283 std::cmp::Ordering::Equal
1284 );
1285 }
1286
1287 mod from_f64 {
1288 use crate::{RealScalar, backends::native::validated::RealNative64StrictFinite};
1289
1290 #[test]
1291 fn test_from_f64_valid_constants() {
1292 let pi = RealNative64StrictFinite::from_f64(std::f64::consts::PI);
1294 assert_eq!(pi.as_ref(), &std::f64::consts::PI);
1295
1296 let e = RealNative64StrictFinite::from_f64(std::f64::consts::E);
1297 assert_eq!(e.as_ref(), &std::f64::consts::E);
1298
1299 let sqrt2 = RealNative64StrictFinite::from_f64(std::f64::consts::SQRT_2);
1300 assert_eq!(sqrt2.as_ref(), &std::f64::consts::SQRT_2);
1301 }
1302
1303 #[test]
1304 fn test_from_f64_valid_values() {
1305 let x = RealNative64StrictFinite::from_f64(42.0);
1307 assert_eq!(x.as_ref(), &42.0);
1308
1309 let y = RealNative64StrictFinite::from_f64(-3.0);
1310 assert_eq!(y.as_ref(), &-3.0);
1311
1312 let z = RealNative64StrictFinite::from_f64(0.0);
1313 assert_eq!(z.as_ref(), &0.0);
1314 }
1315
1316 #[test]
1317 #[should_panic(expected = "RealScalar::from_f64() failed")]
1318 fn test_from_f64_nan_panics() {
1319 let _ = RealNative64StrictFinite::from_f64(f64::NAN);
1320 }
1321
1322 #[test]
1323 #[should_panic(expected = "RealScalar::from_f64() failed")]
1324 fn test_from_f64_infinity_panics() {
1325 let _ = RealNative64StrictFinite::from_f64(f64::INFINITY);
1326 }
1327
1328 #[test]
1329 #[should_panic(expected = "RealScalar::from_f64() failed")]
1330 fn test_from_f64_neg_infinity_panics() {
1331 let _ = RealNative64StrictFinite::from_f64(f64::NEG_INFINITY);
1332 }
1333
1334 #[test]
1335 #[should_panic(expected = "RealScalar::from_f64() failed")]
1336 fn test_from_f64_subnormal_panics() {
1337 let _ = RealNative64StrictFinite::from_f64(f64::MIN_POSITIVE / 2.0);
1339 }
1340
1341 #[test]
1342 fn test_try_from_f64_error_handling() {
1343 assert!(RealNative64StrictFinite::try_from_f64(f64::NAN).is_err());
1345 assert!(RealNative64StrictFinite::try_from_f64(f64::INFINITY).is_err());
1346 assert!(RealNative64StrictFinite::try_from_f64(f64::NEG_INFINITY).is_err());
1347
1348 assert!(RealNative64StrictFinite::try_from_f64(3.0).is_ok());
1350 assert!(RealNative64StrictFinite::try_from_f64(0.0).is_ok());
1351 }
1352 }
1353
1354 mod truncate_to_usize {
1355 use crate::{core::errors::ErrorsRawRealToInteger, kernels::RawRealTrait};
1356
1357 #[test]
1358 fn test_f64_truncate_to_usize_valid() {
1359 assert_eq!(42.0_f64.truncate_to_usize().unwrap(), 42);
1360 assert_eq!(42.9_f64.truncate_to_usize().unwrap(), 42);
1361 assert_eq!(0.0_f64.truncate_to_usize().unwrap(), 0);
1362 }
1363
1364 #[test]
1365 fn test_f64_truncate_to_usize_not_finite() {
1366 assert!(matches!(
1367 f64::NAN.truncate_to_usize(),
1368 Err(ErrorsRawRealToInteger::NotFinite { .. })
1369 ));
1370 assert!(matches!(
1371 f64::INFINITY.truncate_to_usize(),
1372 Err(ErrorsRawRealToInteger::NotFinite { .. })
1373 ));
1374 assert!(matches!(
1375 f64::NEG_INFINITY.truncate_to_usize(),
1376 Err(ErrorsRawRealToInteger::NotFinite { .. })
1377 ));
1378 }
1379
1380 #[test]
1381 fn test_f64_truncate_to_usize_out_of_range() {
1382 assert!(matches!(
1384 (-1.0_f64).truncate_to_usize(),
1385 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1386 ));
1387 assert!(matches!(
1389 ((usize::MAX as f64) + 1.0).truncate_to_usize(),
1390 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1391 ));
1392
1393 assert!(matches!(
1395 (usize::MAX as f64).truncate_to_usize(),
1396 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1397 ));
1398 }
1399 }
1400 }
1401
1402 mod complex {
1403 use super::*;
1404 use crate::{
1405 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
1406 ComplexScalarSetParts,
1407 };
1408 use num::{Complex, Zero};
1409
1410 #[test]
1411 fn real_part() {
1412 let c1 = Complex::new(1.23, 4.56);
1413 assert_eq!(c1.real_part(), 1.23);
1414
1415 let c2 = Complex::new(-7.89, 0.12);
1416 assert_eq!(c2.real_part(), -7.89);
1417
1418 let c3 = Complex::new(0.0, 10.0);
1419 assert_eq!(c3.real_part(), 0.0);
1420
1421 let c_nan_re = Complex::new(f64::NAN, 5.0);
1422 assert!(c_nan_re.real_part().is_nan());
1423
1424 let c_inf_re = Complex::new(f64::INFINITY, 5.0);
1425 assert!(c_inf_re.real_part().is_infinite());
1426 assert!(c_inf_re.real_part().is_sign_positive());
1427
1428 let c_neg_inf_re = Complex::new(f64::NEG_INFINITY, 5.0);
1429 assert!(c_neg_inf_re.real_part().is_infinite());
1430 assert!(c_neg_inf_re.real_part().is_sign_negative());
1431 }
1432
1433 #[test]
1434 fn imag_part() {
1435 let c1 = Complex::new(1.23, 4.56);
1436 assert_eq!(c1.imag_part(), 4.56);
1437
1438 let c2 = Complex::new(7.89, -0.12);
1439 assert_eq!(c2.imag_part(), -0.12);
1440
1441 let c3 = Complex::new(10.0, 0.0);
1442 assert_eq!(c3.imag_part(), 0.0);
1443
1444 let c_nan_im = Complex::new(5.0, f64::NAN);
1445 assert!(c_nan_im.imag_part().is_nan());
1446
1447 let c_inf_im = Complex::new(5.0, f64::INFINITY);
1448 assert!(c_inf_im.imag_part().is_infinite());
1449 assert!(c_inf_im.imag_part().is_sign_positive());
1450
1451 let c_neg_inf_im = Complex::new(5.0, f64::NEG_INFINITY);
1452 assert!(c_neg_inf_im.imag_part().is_infinite());
1453 assert!(c_neg_inf_im.imag_part().is_sign_negative());
1454 }
1455
1456 #[test]
1457 fn try_new_complex() {
1458 let r1 = 1.23;
1459 let i1 = 4.56;
1460 let c1 = Complex::<f64>::try_new_complex(r1, i1).unwrap();
1461 assert_eq!(c1.re, r1);
1462 assert_eq!(c1.im, i1);
1463 assert_eq!(c1.real_part(), r1);
1464 assert_eq!(c1.imag_part(), i1);
1465
1466 let r2 = -7.89;
1467 let i2 = -0.12;
1468 let c2 = Complex::<f64>::try_new_complex(r2, i2).unwrap();
1469 assert_eq!(c2.re, r2);
1470 assert_eq!(c2.im, i2);
1471 assert_eq!(c2.real_part(), r2);
1472 assert_eq!(c2.imag_part(), i2);
1473
1474 let r3 = 0.0;
1475 let i3 = 0.0;
1476 let c3 = Complex::<f64>::try_new_complex(r3, i3).unwrap();
1477 assert_eq!(c3.re, r3);
1478 assert_eq!(c3.im, i3);
1479 assert!(c3.is_zero()); let c_nan_re = Complex::<f64>::try_new_complex(f64::NAN, 5.0).unwrap_err();
1482 assert!(matches!(
1483 c_nan_re,
1484 ErrorsValidationRawComplex::InvalidRealPart { .. }
1485 ));
1486
1487 let c_inf_im = Complex::<f64>::try_new_complex(10.0, f64::INFINITY).unwrap_err();
1488 assert!(matches!(
1489 c_inf_im,
1490 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1491 ));
1492
1493 let c_nan_re_inf_im =
1494 Complex::<f64>::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
1495 assert!(matches!(
1496 c_nan_re_inf_im,
1497 ErrorsValidationRawComplex::InvalidBothParts { .. }
1498 ));
1499 }
1500
1501 #[test]
1502 fn try_new_pure_real() {
1503 let r1 = 1.23;
1504 let c1 = Complex::<f64>::try_new_pure_real(r1).unwrap();
1505 assert_eq!(c1.re, r1);
1506 assert_eq!(c1.im, 0.0);
1507
1508 let c_nan = Complex::<f64>::try_new_pure_real(f64::NAN).unwrap_err();
1509 assert_matches!(
1510 c_nan,
1511 ErrorsValidationRawComplex::InvalidRealPart {
1512 source
1513 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1514 );
1515 }
1516
1517 #[test]
1518 fn try_new_pure_imaginary() {
1519 let i1 = 1.23;
1520 let c1 = Complex::<f64>::try_new_pure_imaginary(i1).unwrap();
1521 assert_eq!(c1.re, 0.0);
1522 assert_eq!(c1.im, i1);
1523
1524 let c_nan = Complex::<f64>::try_new_pure_imaginary(f64::NAN).unwrap_err();
1525 assert_matches!(
1526 c_nan,
1527 ErrorsValidationRawComplex::InvalidImaginaryPart {
1528 source
1529 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1530 );
1531 }
1532
1533 #[test]
1534 fn add_to_real_part() {
1535 let mut c = Complex::new(1.0, 2.0);
1536 c.add_to_real_part(&3.0);
1537 assert_eq!(c.re, 4.0);
1538 assert_eq!(c.im, 2.0);
1539
1540 c.add_to_real_part(&-5.0);
1541 assert_eq!(c.re, -1.0);
1542 assert_eq!(c.im, 2.0);
1543 }
1544
1545 #[cfg(debug_assertions)]
1546 #[test]
1547 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1548 fn add_to_real_part_nan() {
1549 let mut c = Complex::new(1.0, 2.0);
1550 c.add_to_real_part(&f64::NAN);
1551 }
1552
1553 #[test]
1554 fn add_to_imaginary_part() {
1555 let mut c = Complex::new(1.0, 2.0);
1556 c.add_to_imaginary_part(&3.0);
1557 assert_eq!(c.re, 1.0);
1558 assert_eq!(c.im, 5.0);
1559
1560 c.add_to_imaginary_part(&-4.0);
1561 assert_eq!(c.re, 1.0);
1562 assert_eq!(c.im, 1.0);
1563 }
1564
1565 #[cfg(debug_assertions)]
1566 #[test]
1567 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1568 fn add_to_imaginary_part_nan() {
1569 let mut c = Complex::new(1.0, 2.0);
1570 c.add_to_imaginary_part(&f64::NAN);
1571 }
1572
1573 #[test]
1574 fn multiply_real_part() {
1575 let mut c = Complex::new(1.0, 2.0);
1576 c.multiply_real_part(&3.0);
1577 assert_eq!(c.re, 3.0);
1578 assert_eq!(c.im, 2.0);
1579
1580 c.multiply_real_part(&-2.0);
1581 assert_eq!(c.re, -6.0);
1582 assert_eq!(c.im, 2.0);
1583 }
1584
1585 #[cfg(debug_assertions)]
1586 #[test]
1587 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1588 fn multiply_real_part_nan() {
1589 let mut c = Complex::new(1.0, 2.0);
1590 c.multiply_real_part(&f64::NAN);
1591 }
1592
1593 #[test]
1594 fn multiply_imaginary_part() {
1595 let mut c = Complex::new(1.0, 2.0);
1596 c.multiply_imaginary_part(&3.0);
1597 assert_eq!(c.re, 1.0);
1598 assert_eq!(c.im, 6.0);
1599
1600 c.multiply_imaginary_part(&-0.5);
1601 assert_eq!(c.re, 1.0);
1602 assert_eq!(c.im, -3.0);
1603 }
1604
1605 #[cfg(debug_assertions)]
1606 #[test]
1607 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1608 fn multiply_imaginary_part_nan() {
1609 let mut c = Complex::new(1.0, 2.0);
1610 c.multiply_imaginary_part(&f64::NAN);
1611 }
1612
1613 #[test]
1614 fn set_real_part() {
1615 let mut c = Complex::new(1.0, 2.0);
1616 c.set_real_part(3.0);
1617 assert_eq!(c.re, 3.0);
1618 assert_eq!(c.im, 2.0);
1619
1620 c.set_real_part(-4.0);
1621 assert_eq!(c.re, -4.0);
1622 assert_eq!(c.im, 2.0);
1623 }
1624
1625 #[cfg(debug_assertions)]
1626 #[test]
1627 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1628 fn set_real_part_nan() {
1629 let mut c = Complex::new(1.0, 2.0);
1630 c.set_real_part(f64::NAN);
1631 }
1632
1633 #[test]
1634 fn set_imaginary_part() {
1635 let mut c = Complex::new(1.0, 2.0);
1636 c.set_imaginary_part(3.0);
1637 assert_eq!(c.re, 1.0);
1638 assert_eq!(c.im, 3.0);
1639
1640 c.set_imaginary_part(-4.0);
1641 assert_eq!(c.re, 1.0);
1642 assert_eq!(c.im, -4.0);
1643 }
1644
1645 #[cfg(debug_assertions)]
1646 #[test]
1647 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1648 fn set_imaginary_part_nan() {
1649 let mut c = Complex::new(1.0, 2.0);
1650 c.set_imaginary_part(f64::NAN);
1651 }
1652
1653 #[test]
1654 #[allow(clippy::op_ref)]
1655 fn multiply_ref() {
1656 let c1 = Complex::new(1.0, 2.0);
1657 let c2 = Complex::new(3.0, 4.0);
1658 let result = c1 * &c2;
1659 assert_eq!(result, Complex::new(-5.0, 10.0)); }
1661 }
1662}