1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
65 ComplexScalar, Constants, FpScalar, IntegerScalar, MulAddRef, RealScalar, ScalarCore,
66 core::{
67 errors::{
68 ErrorsRawRealToInteger, ErrorsValidationRawComplex, ErrorsValidationRawReal,
69 capture_backtrace,
70 },
71 policies::validate_complex_from_parts,
72 traits::{RawKernel, raw::RawScalarValidate, validation::sealed::NativeReal},
73 },
74 functions::{
75 Clamp, Classify, ExpM1, Hypot, Ln1p, Rounding, Sign, TotalCmp,
76 complex::{
77 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
78 ComplexScalarSetParts,
79 },
80 },
81 kernels::{
82 PrecisionBits, RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow,
83 RawScalarTrait, RawScalarTrigonometric,
84 },
85 scalar_kind,
86};
87use az::CheckedAs;
88use duplicate::duplicate_item;
89use num::{Complex, Zero};
90use num_traits::{Float, FloatConst, MulAdd, MulAddAssign};
91use std::{
92 cmp::Ordering,
93 hash::{Hash, Hasher},
94 num::FpCategory,
95};
96use try_create::IntoInner;
97
98#[derive(Debug, Clone, PartialEq, PartialOrd)]
108pub struct Native<T: NativeReal> {
109 _marker: std::marker::PhantomData<T>,
110}
111
112impl<T: NativeReal> RawKernel for Native<T>
113where
114 T: RawRealTrait<RawComplex = Complex<T>>,
115 Complex<T>: RawComplexTrait<RawReal = T>,
116{
117 type RawReal = T;
119
120 type RawComplex = Complex<T>;
122}
123
124pub type Native64 = Native<f64>;
125pub type Native32 = Native<f32>;
126
127#[duplicate_item(
135 T;
136 [f64];
137 [f32];
138)]
139impl FpScalar for T {
140 type Kind = scalar_kind::Real;
141
142 type RealType = T;
144}
145
146impl<T> FpScalar for Complex<T>
151where
152 Self: RawComplexTrait<RawReal = T>
153 + IntoInner<InnerType = Self>
154 + ScalarCore<RawScalarType = Self>,
155 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar,
156{
157 type Kind = scalar_kind::Complex;
158
159 type RealType = T;
161}
162impl<T: NativeReal> Sign for T {
166 #[inline(always)]
168 fn kernel_copysign(self, sign: &Self) -> Self {
169 self.copysign(*sign)
170 }
171
172 #[inline(always)]
174 fn kernel_is_sign_negative(&self) -> bool {
175 self.is_sign_negative()
176 }
177
178 #[inline(always)]
180 fn kernel_is_sign_positive(&self) -> bool {
181 self.is_sign_positive()
182 }
183
184 #[inline(always)]
191 fn kernel_signum(self) -> Self {
192 self.signum()
193 }
194}
195
196impl<T: NativeReal> Rounding for T {
197 #[inline(always)]
199 fn kernel_ceil(self) -> Self {
200 self.ceil()
201 }
202
203 #[inline(always)]
205 fn kernel_floor(self) -> Self {
206 self.floor()
207 }
208
209 #[inline(always)]
211 fn kernel_fract(self) -> Self {
212 self.fract()
213 }
214
215 #[inline(always)]
217 fn kernel_round(self) -> Self {
218 self.round()
219 }
220
221 #[inline(always)]
240 fn kernel_round_ties_even(self) -> Self {
241 self.round_ties_even_native_real()
242 }
243
244 #[inline(always)]
259 fn kernel_trunc(self) -> Self {
260 self.trunc()
261 }
262}
263
264impl<T: NativeReal> Constants for T {
265 #[inline(always)]
271 fn epsilon() -> Self {
272 <T as Float>::epsilon()
273 }
274
275 #[inline(always)]
277 fn negative_one() -> Self {
278 T::raw_negative_one(T::MANTISSA_DIGITS)
279 }
280
281 #[inline(always)]
283 fn one_div_2() -> Self {
284 T::raw_one_div_2(T::MANTISSA_DIGITS)
285 }
286
287 #[inline(always)]
289 fn two() -> Self {
290 T::raw_two(T::MANTISSA_DIGITS)
291 }
292
293 #[inline(always)]
295 fn max_finite() -> Self {
296 <T as Float>::max_value()
297 }
298
299 #[inline(always)]
301 fn min_finite() -> Self {
302 <T as Float>::min_value()
303 }
304
305 #[inline(always)]
307 fn pi() -> Self {
308 <T as FloatConst>::PI()
309 }
310
311 #[inline(always)]
313 fn two_pi() -> Self {
314 <T as FloatConst>::TAU()
315 }
316
317 #[inline(always)]
319 fn pi_div_2() -> Self {
320 <T as FloatConst>::FRAC_PI_2()
321 }
322
323 #[inline(always)]
325 fn ln_2() -> Self {
326 <T as FloatConst>::LN_2()
327 }
328
329 #[inline(always)]
331 fn ln_10() -> Self {
332 <T as FloatConst>::LN_10()
333 }
334
335 #[inline(always)]
337 fn log10_2() -> Self {
338 <T as FloatConst>::LOG10_2()
339 }
340
341 #[inline(always)]
343 fn log2_10() -> Self {
344 <T as FloatConst>::LOG2_10()
345 }
346
347 #[inline(always)]
349 fn log2_e() -> Self {
350 <T as FloatConst>::LOG2_E()
351 }
352
353 #[inline(always)]
355 fn log10_e() -> Self {
356 <T as FloatConst>::LOG10_E()
357 }
358
359 #[inline(always)]
361 fn e() -> Self {
362 <T as FloatConst>::E()
363 }
364}
365
366impl<T: NativeReal> Clamp for T {
367 #[inline(always)]
385 fn clamp_ref(self, min: &Self, max: &Self) -> Self {
386 <T as Float>::clamp(self, *min, *max)
387 }
388}
389
390impl<T: NativeReal> Classify for T {
391 #[inline(always)]
404 fn classify(&self) -> FpCategory {
405 <T as Float>::classify(*self)
406 }
407}
408
409impl<T: NativeReal> ExpM1 for T {
410 #[inline(always)]
412 fn exp_m1(self) -> Self {
413 <T as Float>::exp_m1(self)
414 }
415}
416
417impl<T: NativeReal> Hypot for T {
418 #[inline(always)]
421 fn hypot(self, other: &Self) -> Self {
422 <T as Float>::hypot(self, *other)
423 }
424}
425
426impl<T: NativeReal> Ln1p for T {
427 #[inline(always)]
429 fn ln_1p(self) -> Self {
430 <T as Float>::ln_1p(self)
431 }
432}
433
434impl<T: NativeReal> TotalCmp for T {
435 #[inline(always)]
436 fn total_cmp(&self, other: &Self) -> Ordering {
437 self.raw_total_cmp(other)
438 }
439}
440
441impl<T: NativeReal> PrecisionBits for T {
442 #[inline(always)]
443 fn precision_bits(&self) -> u32 {
444 T::MANTISSA_DIGITS
445 }
446}
447
448#[duplicate_item(
449 T;
450 [f64];
451 [f32];
452)]
453impl RealScalar for T {
454 type RawReal = T;
455
456 #[inline(always)]
459 fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
460 self.mul_add_assign(*mul, add_mul1 * add_mul2);
461 }
462
463 #[inline(always)]
466 fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
467 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
468 }
469
470 #[inline(always)]
472 fn try_new_raw(value: Self::RawReal) -> Result<Self, ErrorsValidationRawReal<Self::RawReal>> {
473 Ok(value)
474 }
475
476 #[inline(always)]
477 fn target_precision() -> u32 {
478 T::MANTISSA_DIGITS
479 }
480}
481
482impl<T> ComplexScalarConstructors for Complex<T>
483where
484 Self: RawComplexTrait<RawReal = T>
485 + IntoInner<InnerType = Self>
486 + ScalarCore<RawScalarType = Self>,
487 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
488{
489 type RawComplex = Complex<T>;
490
491 fn try_new_complex(
492 real_part: T,
493 imag_part: T,
494 ) -> Result<Self, ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>> {
495 validate_complex_from_parts(&real_part, &imag_part, T::validate_raw_scalar_ref)
496 .map(|_| Complex::new(real_part, imag_part))
497 }
498}
499
500impl<T> ComplexScalarGetParts for Complex<T>
502where
503 Self: RawComplexTrait<RawReal = T>
504 + IntoInner<InnerType = Self>
505 + ScalarCore<RawScalarType = Self>,
506 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
507{
508 #[inline(always)]
510 fn real_part(&self) -> T {
511 self.re
512 }
513
514 #[inline(always)]
516 fn imag_part(&self) -> T {
517 self.im
518 }
519
520 #[inline(always)]
522 fn raw_real_part(&self) -> &T {
523 &self.re
524 }
525
526 #[inline(always)]
528 fn raw_imag_part(&self) -> &T {
529 &self.im
530 }
531}
532
533impl<T> ComplexScalarSetParts for Complex<T>
534where
535 Self: RawComplexTrait<RawReal = T>
536 + IntoInner<InnerType = Self>
537 + ScalarCore<RawScalarType = Self>,
538 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
539{
540 #[inline(always)]
546 fn set_real_part(&mut self, real_part: T) {
547 debug_assert!(
548 real_part.is_finite(),
549 "The real part is not finite (i.e. is infinite or NaN)."
550 );
551 self.re = real_part;
552 }
553
554 #[inline(always)]
560 fn set_imaginary_part(&mut self, imag_part: T) {
561 debug_assert!(
562 imag_part.is_finite(),
563 "The imaginary part is not finite (i.e. is infinite or NaN)."
564 );
565 self.im = imag_part;
566 }
567}
568
569impl<T> ComplexScalarMutateParts for Complex<T>
570where
571 Self: RawComplexTrait<RawReal = T>
572 + IntoInner<InnerType = Self>
573 + ScalarCore<RawScalarType = Self>,
574 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
575{
576 #[inline(always)]
582 fn add_to_real_part(&mut self, c: &T) {
583 self.re += c;
584
585 debug_assert!(
586 self.re.is_finite(),
587 "The real part is not finite (i.e. is infinite or NaN)."
588 );
589 }
590
591 #[inline(always)]
597 fn add_to_imaginary_part(&mut self, c: &T) {
598 self.im += c;
599
600 debug_assert!(
601 self.im.is_finite(),
602 "The imaginary part is not finite (i.e. is infinite or NaN)."
603 );
604 }
605
606 #[inline(always)]
612 fn multiply_real_part(&mut self, c: &T) {
613 self.re *= c;
614
615 debug_assert!(
616 self.re.is_finite(),
617 "The real part is not finite (i.e. is infinite or NaN)."
618 );
619 }
620
621 #[inline(always)]
627 fn multiply_imaginary_part(&mut self, c: &T) {
628 self.im *= c;
629
630 debug_assert!(
631 self.im.is_finite(),
632 "The imaginary part is not finite (i.e. is infinite or NaN)."
633 );
634 }
635}
636
637impl<T> ComplexScalar for Complex<T>
638where
639 Self: RawComplexTrait<RawReal = T>
640 + IntoInner<InnerType = Self>
641 + ScalarCore<RawScalarType = Self>,
642 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
643{
644 fn into_parts(self) -> (Self::RealType, Self::RealType) {
645 (self.re, self.im)
646 }
647}
648
649impl<T> MulAddRef for T
653where
654 T: MulAdd<Output = T> + Copy,
655{
656 #[inline(always)]
660 fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
661 Self::mul_add(self, *b, *c)
662 }
663}
664impl<T: NativeReal> RawScalarTrigonometric for T {
671 #[duplicate_item(
672 unchecked_method method;
673 [unchecked_sin] [sin];
674 [unchecked_asin] [asin];
675 [unchecked_cos] [cos];
676 [unchecked_acos] [acos];
677 [unchecked_tan] [tan];
678 [unchecked_atan] [atan];
679 )]
680 #[inline(always)]
681 fn unchecked_method(self) -> Self {
682 T::method(self)
683 }
684}
685
686impl<T: NativeReal> RawScalarTrigonometric for Complex<T> {
687 #[duplicate_item(
688 unchecked_method method;
689 [unchecked_sin] [sin];
690 [unchecked_asin] [asin];
691 [unchecked_cos] [cos];
692 [unchecked_acos] [acos];
693 [unchecked_tan] [tan];
694 [unchecked_atan] [atan];
695 )]
696 #[inline(always)]
697 fn unchecked_method(self) -> Self {
698 Complex::<T>::method(self)
699 }
700}
701
702impl<T: NativeReal> RawScalarHyperbolic for T {
703 #[duplicate_item(
704 unchecked_method method;
705 [unchecked_sinh] [sinh];
706 [unchecked_asinh] [asinh];
707 [unchecked_cosh] [cosh];
708 [unchecked_acosh] [acosh];
709 [unchecked_tanh] [tanh];
710 [unchecked_atanh] [atanh];
711 )]
712 #[inline(always)]
713 fn unchecked_method(self) -> Self {
714 T::method(self)
715 }
716}
717
718impl<T: NativeReal> RawScalarHyperbolic for Complex<T> {
719 #[duplicate_item(
720 unchecked_method method;
721 [unchecked_sinh] [sinh];
722 [unchecked_asinh] [asinh];
723 [unchecked_cosh] [cosh];
724 [unchecked_acosh] [acosh];
725 [unchecked_tanh] [tanh];
726 [unchecked_atanh] [atanh];
727 )]
728 #[inline(always)]
729 fn unchecked_method(self) -> Self {
730 Complex::<T>::method(self)
731 }
732}
733
734impl<T: NativeReal> RawScalarPow for T {
735 #[duplicate_item(
736 unchecked_method exponent_type;
737 [unchecked_pow_exponent_i8] [i8];
738 [unchecked_pow_exponent_i16] [i16];
739 [unchecked_pow_exponent_u8] [u8];
740 [unchecked_pow_exponent_u16] [u16];
741 )]
742 #[inline(always)]
743 fn unchecked_method(self, exponent: &exponent_type) -> T {
744 T::powi(self, (*exponent).into())
745 }
746
747 #[inline(always)]
748 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
749 T::powi(self, *exponent)
750 }
751
752 #[duplicate_item(
753 unchecked_method exponent_type;
754 [unchecked_pow_exponent_i64] [i64];
755 [unchecked_pow_exponent_i128] [i128];
756 [unchecked_pow_exponent_isize] [isize];
757 [unchecked_pow_exponent_u32] [u32];
758 [unchecked_pow_exponent_u64] [u64];
759 [unchecked_pow_exponent_u128] [u128];
760 [unchecked_pow_exponent_usize] [usize];
761 )]
762 #[inline(always)]
763 fn unchecked_method(self, exponent: &exponent_type) -> T {
764 T::powi(
765 self,
766 (*exponent)
767 .try_into()
768 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
769 )
770 }
771}
772
773impl<T: NativeReal> RawScalarValidate for T {
774 type ValidationError = ErrorsValidationRawReal<T>;
775
776 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
777 match self.classify() {
778 FpCategory::Nan => Err(ErrorsValidationRawReal::IsNaN {
779 value: *self,
780 backtrace: capture_backtrace(),
781 }),
782 FpCategory::Infinite => {
783 if self.is_sign_positive() {
784 Err(ErrorsValidationRawReal::IsPosInfinity {
785 backtrace: capture_backtrace(),
786 })
787 } else {
788 Err(ErrorsValidationRawReal::IsNegInfinity {
789 backtrace: capture_backtrace(),
790 })
791 }
792 }
793 FpCategory::Subnormal => Err(ErrorsValidationRawReal::IsSubnormal {
794 value: *self,
795 backtrace: capture_backtrace(),
796 }),
797 FpCategory::Normal | FpCategory::Zero => Ok(()),
798 }
799 }
800}
801
802#[inline(always)]
803fn debug_assert_if_invalid_precision<T: NativeReal>(precision: u32) {
804 debug_assert_eq!(
805 precision,
806 T::MANTISSA_DIGITS,
807 "Precision {precision} must be equal to the mantissa digits for type {} (mantissa digits = {}).",
808 std::any::type_name::<T>(),
809 T::MANTISSA_DIGITS
810 );
811}
812
813impl<T: NativeReal> RawScalarTrait for T {
814 #[inline(always)]
815 fn raw_zero(_precision: u32) -> T {
816 debug_assert_if_invalid_precision::<T>(_precision);
817 T::zero()
818 }
819
820 #[inline(always)]
821 fn is_zero(&self) -> bool {
822 <Self as Zero>::is_zero(self)
823 }
824 #[inline(always)]
825 fn raw_one(_precision: u32) -> T {
826 debug_assert_if_invalid_precision::<T>(_precision);
827 T::one()
828 }
829
830 #[duplicate_item(
831 unchecked_method method;
832 [unchecked_reciprocal] [recip];
833 [unchecked_exp] [exp];
834 [unchecked_sqrt] [sqrt];
835 [unchecked_ln] [ln];
836 [unchecked_log2] [log2];
837 [unchecked_log10] [log10];
838 )]
839 #[inline(always)]
840 fn unchecked_method(self) -> T {
841 <T as Float>::method(self)
842 }
843
844 #[inline(always)]
848 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
849 Float::mul_add(self, *b, *c)
850 }
851
852 #[inline(always)]
853 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
854 debug_assert!(
855 self.is_finite(),
856 concat!(
857 "Hashing a non-finite ",
858 stringify!(T),
859 " floating-point value (i.e., NaN or Infinity) may lead to inconsistent results."
860 )
861 );
862 let zero = T::zero();
863 if self == &zero {
864 zero.to_bits_native_real().hash(state);
866 } else {
867 self.to_bits_native_real().hash(state);
868 }
869 }
870}
871
872#[duplicate_item(
873 T cast_int_to_float from_raw_real;
874 [f64] [to_f64()] [from_f64];
875 [f32] [to_f32()] [from_f32];
876)]
877impl RawRealTrait for T {
878 type RawComplex = Complex<T>;
879
880 #[inline(always)]
881 fn unchecked_abs(self) -> Self {
882 <T as Float>::abs(self)
883 }
884
885 #[inline(always)]
886 fn unchecked_atan2(self, denominator: &Self) -> Self {
887 <T as Float>::atan2(self, *denominator)
888 }
889
890 #[inline(always)]
891 fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
892 <T as Float>::powf(self, *exponent)
893 }
894
895 #[inline(always)]
896 fn unchecked_hypot(self, other: &Self) -> Self {
897 <T as Float>::hypot(self, *other)
898 }
899
900 #[inline(always)]
901 fn unchecked_ln_1p(self) -> Self {
902 <T as Float>::ln_1p(self)
903 }
904
905 #[inline(always)]
906 fn unchecked_exp_m1(self) -> Self {
907 <T as Float>::exp_m1(self)
908 }
909
910 #[inline(always)]
913 fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
914 self.mul_add_assign(*mul, add_mul1 * add_mul2);
915 }
916
917 #[inline(always)]
920 fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
921 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
922 }
923
924 #[inline(always)]
925 fn raw_total_cmp(&self, other: &Self) -> Ordering {
926 T::total_cmp(self, other)
927 }
928
929 #[inline(always)]
931 fn raw_clamp(self, min: &Self, max: &Self) -> Self {
932 <T as Float>::clamp(self, *min, *max)
933 }
934
935 #[inline(always)]
936 fn raw_classify(&self) -> FpCategory {
937 <T as Float>::classify(*self)
938 }
939
940 #[inline(always)]
941 fn raw_two(_precision: u32) -> Self {
942 debug_assert_if_invalid_precision::<T>(_precision);
943 2.
944 }
945
946 #[inline(always)]
947 fn raw_one_div_2(_precision: u32) -> Self {
948 debug_assert_if_invalid_precision::<T>(_precision);
949 0.5
950 }
951
952 #[inline(always)]
953 fn raw_pi(_precision: u32) -> Self {
954 debug_assert_if_invalid_precision::<T>(_precision);
955 <T as FloatConst>::PI()
956 }
957
958 #[inline(always)]
959 fn raw_two_pi(_precision: u32) -> Self {
960 debug_assert_if_invalid_precision::<T>(_precision);
961 <T as FloatConst>::TAU()
962 }
963
964 #[inline(always)]
965 fn raw_pi_div_2(_precision: u32) -> Self {
966 debug_assert_if_invalid_precision::<T>(_precision);
967 <T as FloatConst>::FRAC_PI_2()
968 }
969
970 #[inline(always)]
971 fn raw_max_finite(_precision: u32) -> Self {
972 debug_assert_if_invalid_precision::<T>(_precision);
973 <T as Float>::max_value()
974 }
975
976 #[inline(always)]
977 fn raw_min_finite(_precision: u32) -> Self {
978 debug_assert_if_invalid_precision::<T>(_precision);
979 <T as Float>::min_value()
980 }
981
982 #[inline(always)]
983 fn raw_epsilon(_precision: u32) -> Self {
984 debug_assert_if_invalid_precision::<T>(_precision);
985 <T as Float>::epsilon()
986 }
987
988 #[inline(always)]
989 fn raw_ln_2(_precision: u32) -> Self {
990 debug_assert_if_invalid_precision::<T>(_precision);
991 <T as FloatConst>::LN_2()
992 }
993
994 #[inline(always)]
995 fn raw_ln_10(_precision: u32) -> Self {
996 debug_assert_if_invalid_precision::<T>(_precision);
997 <T as FloatConst>::LN_10()
998 }
999
1000 #[inline(always)]
1001 fn raw_log10_2(_precision: u32) -> Self {
1002 debug_assert_if_invalid_precision::<T>(_precision);
1003 <T as FloatConst>::LOG10_2()
1004 }
1005
1006 #[inline(always)]
1007 fn raw_log2_10(_precision: u32) -> Self {
1008 debug_assert_if_invalid_precision::<T>(_precision);
1009 <T as FloatConst>::LOG2_10()
1010 }
1011
1012 #[inline(always)]
1013 fn raw_log2_e(_precision: u32) -> Self {
1014 debug_assert_if_invalid_precision::<T>(_precision);
1015 <T as FloatConst>::LOG2_E()
1016 }
1017
1018 #[inline(always)]
1019 fn raw_log10_e(_precision: u32) -> Self {
1020 debug_assert_if_invalid_precision::<T>(_precision);
1021 <T as FloatConst>::LOG10_E()
1022 }
1023
1024 #[inline(always)]
1025 fn raw_e(_precision: u32) -> Self {
1026 debug_assert_if_invalid_precision::<T>(_precision);
1027 <T as FloatConst>::E()
1028 }
1029
1030 #[inline(always)]
1031 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<T, usize>> {
1032 if !self.is_finite() {
1033 return Err(ErrorsRawRealToInteger::NotFinite {
1034 value: self,
1035 backtrace: capture_backtrace(),
1036 });
1037 }
1038
1039 match self.checked_as::<usize>() {
1040 Some(value) => Ok(value),
1041 None => Err(ErrorsRawRealToInteger::OutOfRange {
1042 value: self,
1043 min: usize::MIN,
1044 max: usize::MAX,
1045 backtrace: capture_backtrace(),
1046 }),
1047 }
1048 }
1049
1050 fn unchecked_mul_assign_integer<I>(&mut self, integer: I)
1051 where
1052 I: IntegerScalar,
1053 {
1054 let as_raw_real = integer
1055 .cast_int_to_float
1056 .expect("Failed to cast integer to raw float");
1057 debug_assert!(
1058 I::from_raw_real(as_raw_real) == Some(integer),
1059 "unchecked_mul_assign_integer requires an exact conversion, but the integer is not exactly representable in the target raw real type"
1060 );
1061 *self *= as_raw_real;
1062 }
1063
1064 fn unchecked_div_assign_integer<I>(&mut self, integer: I)
1065 where
1066 I: IntegerScalar,
1067 {
1068 let as_raw_real = integer
1069 .cast_int_to_float
1070 .expect("Failed to cast integer to raw float");
1071 debug_assert!(
1072 I::from_raw_real(as_raw_real) == Some(integer),
1073 "unchecked_div_assign_integer requires an exact conversion, but the integer is not exactly representable in the target raw real type"
1074 );
1075 *self /= as_raw_real;
1076 }
1077}
1078
1079impl<T: NativeReal> RawScalarPow for Complex<T> {
1080 #[duplicate_item(
1081 unchecked_method exponent_type;
1082 [unchecked_pow_exponent_i8] [i8];
1083 [unchecked_pow_exponent_i16] [i16];
1084 )]
1085 #[inline(always)]
1086 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1087 Complex::<T>::powi(&self, (*exponent).into())
1088 }
1089
1090 #[inline(always)]
1091 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
1092 Complex::<T>::powi(&self, *exponent)
1093 }
1094
1095 #[duplicate_item(
1096 unchecked_method exponent_type;
1097 [unchecked_pow_exponent_i64] [i64];
1098 [unchecked_pow_exponent_i128] [i128];
1099 [unchecked_pow_exponent_isize] [isize];
1100 )]
1101 #[inline(always)]
1102 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1103 Complex::<T>::powi(
1104 &self,
1105 (*exponent)
1106 .try_into()
1107 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
1108 )
1109 }
1110
1111 #[duplicate_item(
1112 unchecked_method exponent_type;
1113 [unchecked_pow_exponent_u8] [u8];
1114 [unchecked_pow_exponent_u16] [u16];
1115 )]
1116 #[inline(always)]
1117 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1118 Complex::<T>::powu(&self, (*exponent).into())
1119 }
1120
1121 #[inline(always)]
1122 fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
1123 Complex::<T>::powu(&self, *exponent)
1124 }
1125
1126 #[duplicate_item(
1127 unchecked_method exponent_type;
1128 [unchecked_pow_exponent_u64] [u64];
1129 [unchecked_pow_exponent_u128] [u128];
1130 [unchecked_pow_exponent_usize] [usize];
1131 )]
1132 #[inline(always)]
1133 fn unchecked_method(self, exponent: &exponent_type) -> Self {
1134 Complex::<T>::powu(
1135 &self,
1136 (*exponent)
1137 .try_into()
1138 .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
1139 )
1140 }
1141}
1142
1143impl<T: NativeReal> RawScalarValidate for Complex<T> {
1144 type ValidationError = ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>;
1145
1146 #[inline(always)]
1147 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
1148 validate_complex_from_parts(&self.re, &self.im, T::validate_raw_scalar_ref)
1149 }
1150}
1151
1152impl<T: NativeReal> RawScalarTrait for Complex<T> {
1153 #[inline(always)]
1154 fn raw_zero(_precision: u32) -> Self {
1155 debug_assert_if_invalid_precision::<T>(_precision);
1156 Complex::new(T::zero(), T::zero())
1157 }
1158
1159 #[inline(always)]
1160 fn is_zero(&self) -> bool {
1161 <Self as Zero>::is_zero(self)
1162 }
1163
1164 #[inline(always)]
1165 fn raw_one(_precision: u32) -> Self {
1166 debug_assert_if_invalid_precision::<T>(_precision);
1167 Complex::new(T::one(), T::zero())
1168 }
1169
1170 #[duplicate_item(
1171 unchecked_method method;
1172 [unchecked_exp] [exp];
1173 [unchecked_sqrt] [sqrt];
1174 [unchecked_ln] [ln];
1175 [unchecked_log10] [log10];
1176 )]
1177 #[inline(always)]
1178 fn unchecked_method(self) -> Self {
1179 Complex::<T>::method(self)
1180 }
1181
1182 #[inline(always)]
1183 fn unchecked_reciprocal(self) -> Self {
1184 Complex::<T>::inv(&self)
1185 }
1186
1187 #[inline(always)]
1188 fn unchecked_log2(self) -> Self {
1189 Complex::<T>::ln(self) / <T as FloatConst>::LN_2()
1190 }
1191
1192 #[inline(always)]
1196 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
1197 Complex::<T>::mul_add(self, *b, *c)
1198 }
1199
1200 #[inline(always)]
1201 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
1202 self.re.compute_hash_raw_scalar(state);
1203 self.im.compute_hash_raw_scalar(state);
1204 }
1205}
1206
1207impl<T> RawComplexTrait for Complex<T>
1208where
1209 T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RawRealTrait<RawComplex = Self>,
1211{
1212 type RawReal = T;
1213
1214 fn new_unchecked_raw_complex(real: T, imag: T) -> Self {
1215 Complex::<T>::new(real, imag)
1216 }
1217
1218 fn mut_raw_real_part(&mut self) -> &mut T {
1220 &mut self.re
1221 }
1222
1223 fn mut_raw_imag_part(&mut self) -> &mut T {
1225 &mut self.im
1226 }
1227
1228 #[inline(always)]
1229 fn unchecked_abs(self) -> T {
1230 Complex::<T>::norm(self)
1231 }
1232
1233 #[inline(always)]
1234 fn raw_real_part(&self) -> &T {
1235 &self.re
1236 }
1237
1238 #[inline(always)]
1239 fn raw_imag_part(&self) -> &T {
1240 &self.im
1241 }
1242
1243 #[inline(always)]
1244 fn unchecked_arg(self) -> T {
1245 Complex::<T>::arg(self)
1246 }
1247
1248 #[inline(always)]
1249 fn unchecked_pow_exponent_real(self, exponent: &T) -> Self {
1250 Complex::<T>::powf(self, *exponent)
1251 }
1252}
1253
1254#[cfg(test)]
1255mod tests {
1256 use crate::{
1257 core::errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal},
1258 functions::TotalCmp,
1259 };
1260 use std::assert_matches;
1261
1262 mod real {
1263 use super::*;
1264 use crate::Constants;
1265
1266 #[test]
1267 fn test_constants() {
1268 assert_eq!(<f64 as Constants>::epsilon(), f64::EPSILON);
1269 assert_eq!(<f64 as Constants>::negative_one(), -1.0);
1270 assert_eq!(<f64 as Constants>::one_div_2(), 0.5);
1271 assert_eq!(<f64 as Constants>::two(), 2.0);
1272 assert_eq!(<f64 as Constants>::max_finite(), f64::MAX);
1273 assert_eq!(<f64 as Constants>::min_finite(), f64::MIN);
1274 assert_eq!(<f64 as Constants>::pi(), std::f64::consts::PI);
1275 assert_eq!(<f64 as Constants>::two_pi(), std::f64::consts::PI * 2.0);
1276 assert_eq!(<f64 as Constants>::pi_div_2(), std::f64::consts::FRAC_PI_2);
1277 assert_eq!(<f64 as Constants>::ln_2(), std::f64::consts::LN_2);
1278 assert_eq!(<f64 as Constants>::ln_10(), std::f64::consts::LN_10);
1279 assert_eq!(<f64 as Constants>::log10_2(), std::f64::consts::LOG10_2);
1280 assert_eq!(<f64 as Constants>::log2_10(), std::f64::consts::LOG2_10);
1281 assert_eq!(<f64 as Constants>::log2_e(), std::f64::consts::LOG2_E);
1282 assert_eq!(<f64 as Constants>::log10_e(), std::f64::consts::LOG10_E);
1283 assert_eq!(<f64 as Constants>::e(), std::f64::consts::E);
1284 }
1285
1286 #[test]
1287 #[allow(clippy::op_ref)]
1288 fn multiply_ref() {
1289 let a = 2.0f64;
1290 let b = 3.0f64;
1291 let result = a * &b;
1292 assert_eq!(result, 6.0);
1293 }
1294
1295 #[test]
1296 fn total_cmp() {
1297 let a = 2.0f64;
1298 let b = 3.0f64;
1299 assert_eq!(
1300 <f64 as TotalCmp>::total_cmp(&a, &b),
1301 std::cmp::Ordering::Less
1302 );
1303 assert_eq!(
1304 <f64 as TotalCmp>::total_cmp(&b, &a),
1305 std::cmp::Ordering::Greater
1306 );
1307 assert_eq!(
1308 <f64 as TotalCmp>::total_cmp(&a, &a),
1309 std::cmp::Ordering::Equal
1310 );
1311 }
1312
1313 mod from_f64 {
1314 use crate::{backends::native::validated::RealNative64StrictFinite, *};
1315
1316 #[test]
1317 fn test_from_f64_valid_constants() {
1318 let pi = RealNative64StrictFinite::from_f64(std::f64::consts::PI);
1320 assert_eq!(pi.as_raw_scalar_ref(), &std::f64::consts::PI);
1321
1322 let e = RealNative64StrictFinite::from_f64(std::f64::consts::E);
1323 assert_eq!(e.as_raw_scalar_ref(), &std::f64::consts::E);
1324
1325 let sqrt2 = RealNative64StrictFinite::from_f64(std::f64::consts::SQRT_2);
1326 assert_eq!(sqrt2.as_raw_scalar_ref(), &std::f64::consts::SQRT_2);
1327 }
1328
1329 #[test]
1330 fn test_from_f64_valid_values() {
1331 let x = RealNative64StrictFinite::from_f64(42.0);
1333 assert_eq!(x.as_raw_scalar_ref(), &42.0);
1334
1335 let y = RealNative64StrictFinite::from_f64(-3.0);
1336 assert_eq!(y.as_raw_scalar_ref(), &-3.0);
1337
1338 let z = RealNative64StrictFinite::from_f64(0.0);
1339 assert_eq!(z.as_raw_scalar_ref(), &0.0);
1340 }
1341
1342 #[test]
1343 #[should_panic(
1344 expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1345 )]
1346 fn test_from_f64_nan_panics() {
1347 let _ = RealNative64StrictFinite::from_f64(f64::NAN);
1348 }
1349
1350 #[test]
1351 #[should_panic(
1352 expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1353 )]
1354 fn test_from_f64_infinity_panics() {
1355 let _ = RealNative64StrictFinite::from_f64(f64::INFINITY);
1356 }
1357
1358 #[test]
1359 #[should_panic(
1360 expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1361 )]
1362 fn test_from_f64_neg_infinity_panics() {
1363 let _ = RealNative64StrictFinite::from_f64(f64::NEG_INFINITY);
1364 }
1365
1366 #[test]
1367 #[should_panic(
1368 expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1369 )]
1370 fn test_from_f64_subnormal_panics() {
1371 let _ = RealNative64StrictFinite::from_f64(f64::MIN_POSITIVE / 2.0);
1373 }
1374
1375 #[test]
1376 fn test_try_from_f64_error_handling() {
1377 assert!(RealNative64StrictFinite::try_from_f64(f64::NAN).is_err());
1379 assert!(RealNative64StrictFinite::try_from_f64(f64::INFINITY).is_err());
1380 assert!(RealNative64StrictFinite::try_from_f64(f64::NEG_INFINITY).is_err());
1381
1382 assert!(RealNative64StrictFinite::try_from_f64(3.0).is_ok());
1384 assert!(RealNative64StrictFinite::try_from_f64(0.0).is_ok());
1385 }
1386 }
1387
1388 mod truncate_to_usize {
1389 use crate::{core::errors::ErrorsRawRealToInteger, kernels::RawRealTrait};
1390
1391 #[test]
1392 fn test_f64_truncate_to_usize_valid() {
1393 assert_eq!(42.0_f64.truncate_to_usize().unwrap(), 42);
1394 assert_eq!(42.9_f64.truncate_to_usize().unwrap(), 42);
1395 assert_eq!(0.0_f64.truncate_to_usize().unwrap(), 0);
1396 }
1397
1398 #[test]
1399 fn test_f64_truncate_to_usize_not_finite() {
1400 assert!(matches!(
1401 f64::NAN.truncate_to_usize(),
1402 Err(ErrorsRawRealToInteger::NotFinite { .. })
1403 ));
1404 assert!(matches!(
1405 f64::INFINITY.truncate_to_usize(),
1406 Err(ErrorsRawRealToInteger::NotFinite { .. })
1407 ));
1408 assert!(matches!(
1409 f64::NEG_INFINITY.truncate_to_usize(),
1410 Err(ErrorsRawRealToInteger::NotFinite { .. })
1411 ));
1412 }
1413
1414 #[test]
1415 fn test_f64_truncate_to_usize_out_of_range() {
1416 assert!(matches!(
1418 (-1.0_f64).truncate_to_usize(),
1419 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1420 ));
1421 assert!(matches!(
1423 ((usize::MAX as f64) + 1.0).truncate_to_usize(),
1424 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1425 ));
1426
1427 assert!(matches!(
1429 (usize::MAX as f64).truncate_to_usize(),
1430 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1431 ));
1432 }
1433 }
1434
1435 mod mul_assign_integer {
1436 use crate::kernels::RawRealTrait;
1437
1438 #[test]
1439 fn f64_multiplies_by_signed_integer() {
1440 let mut real = 3.5_f64;
1441 real.unchecked_mul_assign_integer(-4_i32);
1442 assert_eq!(real, -14.0);
1443 }
1444
1445 #[test]
1446 fn f32_multiplies_by_unsigned_integer() {
1447 let mut real = 3.5_f32;
1448 real.unchecked_mul_assign_integer(4_u16);
1449 assert_eq!(real, 14.0);
1450 }
1451
1452 #[test]
1453 fn zeroes_the_value() {
1454 let mut real_f64 = 3.5_f64;
1455 let mut real_f32 = 3.5_f32;
1456
1457 real_f64.unchecked_mul_assign_integer(0_i8);
1458 real_f32.unchecked_mul_assign_integer(0_i8);
1459
1460 assert_eq!(real_f64, 0.0);
1461 assert_eq!(real_f32, 0.0);
1462 }
1463
1464 #[test]
1465 fn f64_accepts_integer_at_precision_boundary() {
1466 let mut real = 1.0_f64;
1467 real.unchecked_mul_assign_integer(1_i128 << 53);
1468 assert_eq!(real, 9_007_199_254_740_992.0);
1469 }
1470
1471 #[test]
1472 #[cfg(debug_assertions)]
1473 #[should_panic(expected = "unchecked_mul_assign_integer requires an exact conversion")]
1474 fn f64_panics_on_non_exact_conversion() {
1475 let mut real = 1.0_f64;
1476 real.unchecked_mul_assign_integer((1_i128 << 53) + 1);
1477 }
1478 }
1479
1480 mod div_assign_integer {
1481 use crate::kernels::RawRealTrait;
1482
1483 #[test]
1484 fn f64_divides_by_signed_integer() {
1485 let mut real = 14.0_f64;
1486 real.unchecked_div_assign_integer(-4_i32);
1487 assert_eq!(real, -3.5);
1488 }
1489
1490 #[test]
1491 fn f32_divides_by_unsigned_integer() {
1492 let mut real = 14.0_f32;
1493 real.unchecked_div_assign_integer(4_u16);
1494 assert_eq!(real, 3.5);
1495 }
1496
1497 #[test]
1498 fn f64_accepts_integer_at_precision_boundary() {
1499 let mut real = 9_007_199_254_740_992.0_f64;
1500 real.unchecked_div_assign_integer(1_i128 << 53);
1501 assert_eq!(real, 1.0);
1502 }
1503
1504 #[test]
1505 #[cfg(debug_assertions)]
1506 #[should_panic(expected = "unchecked_div_assign_integer requires an exact conversion")]
1507 fn f64_panics_on_non_exact_conversion() {
1508 let mut real = 1.0_f64;
1509 real.unchecked_div_assign_integer((1_i128 << 53) + 1);
1510 }
1511 }
1512
1513 mod mul_integer {
1514 use crate::kernels::RawRealTrait;
1515
1516 #[test]
1517 fn f64_returns_product_without_mutating_in_place() {
1518 let real = 3.5_f64;
1519 assert_eq!(real.unchecked_mul_integer(-4_i32), -14.0);
1520 }
1521 }
1522
1523 mod div_integer {
1524 use crate::kernels::RawRealTrait;
1525
1526 #[test]
1527 fn f64_returns_quotient_without_mutating_in_place() {
1528 let real = 14.0_f64;
1529 assert_eq!(real.unchecked_div_integer(-4_i32), -3.5);
1530 }
1531 }
1532 }
1533
1534 mod complex {
1535 use super::*;
1536 use crate::{
1537 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
1538 ComplexScalarSetParts,
1539 };
1540 use num::{Complex, Zero};
1541
1542 #[test]
1543 fn real_part() {
1544 let c1 = Complex::new(1.23, 4.56);
1545 assert_eq!(c1.real_part(), 1.23);
1546
1547 let c2 = Complex::new(-7.89, 0.12);
1548 assert_eq!(c2.real_part(), -7.89);
1549
1550 let c3 = Complex::new(0.0, 10.0);
1551 assert_eq!(c3.real_part(), 0.0);
1552
1553 let c_nan_re = Complex::new(f64::NAN, 5.0);
1554 assert!(c_nan_re.real_part().is_nan());
1555
1556 let c_inf_re = Complex::new(f64::INFINITY, 5.0);
1557 assert!(c_inf_re.real_part().is_infinite());
1558 assert!(c_inf_re.real_part().is_sign_positive());
1559
1560 let c_neg_inf_re = Complex::new(f64::NEG_INFINITY, 5.0);
1561 assert!(c_neg_inf_re.real_part().is_infinite());
1562 assert!(c_neg_inf_re.real_part().is_sign_negative());
1563 }
1564
1565 #[test]
1566 fn imag_part() {
1567 let c1 = Complex::new(1.23, 4.56);
1568 assert_eq!(c1.imag_part(), 4.56);
1569
1570 let c2 = Complex::new(7.89, -0.12);
1571 assert_eq!(c2.imag_part(), -0.12);
1572
1573 let c3 = Complex::new(10.0, 0.0);
1574 assert_eq!(c3.imag_part(), 0.0);
1575
1576 let c_nan_im = Complex::new(5.0, f64::NAN);
1577 assert!(c_nan_im.imag_part().is_nan());
1578
1579 let c_inf_im = Complex::new(5.0, f64::INFINITY);
1580 assert!(c_inf_im.imag_part().is_infinite());
1581 assert!(c_inf_im.imag_part().is_sign_positive());
1582
1583 let c_neg_inf_im = Complex::new(5.0, f64::NEG_INFINITY);
1584 assert!(c_neg_inf_im.imag_part().is_infinite());
1585 assert!(c_neg_inf_im.imag_part().is_sign_negative());
1586 }
1587
1588 #[test]
1589 fn try_new_complex() {
1590 let r1 = 1.23;
1591 let i1 = 4.56;
1592 let c1 = Complex::<f64>::try_new_complex(r1, i1).unwrap();
1593 assert_eq!(c1.re, r1);
1594 assert_eq!(c1.im, i1);
1595 assert_eq!(c1.real_part(), r1);
1596 assert_eq!(c1.imag_part(), i1);
1597
1598 let r2 = -7.89;
1599 let i2 = -0.12;
1600 let c2 = Complex::<f64>::try_new_complex(r2, i2).unwrap();
1601 assert_eq!(c2.re, r2);
1602 assert_eq!(c2.im, i2);
1603 assert_eq!(c2.real_part(), r2);
1604 assert_eq!(c2.imag_part(), i2);
1605
1606 let r3 = 0.0;
1607 let i3 = 0.0;
1608 let c3 = Complex::<f64>::try_new_complex(r3, i3).unwrap();
1609 assert_eq!(c3.re, r3);
1610 assert_eq!(c3.im, i3);
1611 assert!(c3.is_zero()); let c_nan_re = Complex::<f64>::try_new_complex(f64::NAN, 5.0).unwrap_err();
1614 assert!(matches!(
1615 c_nan_re,
1616 ErrorsValidationRawComplex::InvalidRealPart { .. }
1617 ));
1618
1619 let c_inf_im = Complex::<f64>::try_new_complex(10.0, f64::INFINITY).unwrap_err();
1620 assert!(matches!(
1621 c_inf_im,
1622 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1623 ));
1624
1625 let c_nan_re_inf_im =
1626 Complex::<f64>::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
1627 assert!(matches!(
1628 c_nan_re_inf_im,
1629 ErrorsValidationRawComplex::InvalidBothParts { .. }
1630 ));
1631 }
1632
1633 #[test]
1634 fn try_new_pure_real() {
1635 let r1 = 1.23;
1636 let c1 = Complex::<f64>::try_new_pure_real(r1).unwrap();
1637 assert_eq!(c1.re, r1);
1638 assert_eq!(c1.im, 0.0);
1639
1640 let c_nan = Complex::<f64>::try_new_pure_real(f64::NAN).unwrap_err();
1641 assert_matches!(
1642 c_nan,
1643 ErrorsValidationRawComplex::InvalidRealPart {
1644 source
1645 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1646 );
1647 }
1648
1649 #[test]
1650 fn try_new_pure_imaginary() {
1651 let i1 = 1.23;
1652 let c1 = Complex::<f64>::try_new_pure_imaginary(i1).unwrap();
1653 assert_eq!(c1.re, 0.0);
1654 assert_eq!(c1.im, i1);
1655
1656 let c_nan = Complex::<f64>::try_new_pure_imaginary(f64::NAN).unwrap_err();
1657 assert_matches!(
1658 c_nan,
1659 ErrorsValidationRawComplex::InvalidImaginaryPart {
1660 source
1661 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1662 );
1663 }
1664
1665 #[test]
1666 fn add_to_real_part() {
1667 let mut c = Complex::new(1.0, 2.0);
1668 c.add_to_real_part(&3.0);
1669 assert_eq!(c.re, 4.0);
1670 assert_eq!(c.im, 2.0);
1671
1672 c.add_to_real_part(&-5.0);
1673 assert_eq!(c.re, -1.0);
1674 assert_eq!(c.im, 2.0);
1675 }
1676
1677 #[cfg(debug_assertions)]
1678 #[test]
1679 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1680 fn add_to_real_part_nan() {
1681 let mut c = Complex::new(1.0, 2.0);
1682 c.add_to_real_part(&f64::NAN);
1683 }
1684
1685 #[test]
1686 fn add_to_imaginary_part() {
1687 let mut c = Complex::new(1.0, 2.0);
1688 c.add_to_imaginary_part(&3.0);
1689 assert_eq!(c.re, 1.0);
1690 assert_eq!(c.im, 5.0);
1691
1692 c.add_to_imaginary_part(&-4.0);
1693 assert_eq!(c.re, 1.0);
1694 assert_eq!(c.im, 1.0);
1695 }
1696
1697 #[cfg(debug_assertions)]
1698 #[test]
1699 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1700 fn add_to_imaginary_part_nan() {
1701 let mut c = Complex::new(1.0, 2.0);
1702 c.add_to_imaginary_part(&f64::NAN);
1703 }
1704
1705 #[test]
1706 fn multiply_real_part() {
1707 let mut c = Complex::new(1.0, 2.0);
1708 c.multiply_real_part(&3.0);
1709 assert_eq!(c.re, 3.0);
1710 assert_eq!(c.im, 2.0);
1711
1712 c.multiply_real_part(&-2.0);
1713 assert_eq!(c.re, -6.0);
1714 assert_eq!(c.im, 2.0);
1715 }
1716
1717 #[cfg(debug_assertions)]
1718 #[test]
1719 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1720 fn multiply_real_part_nan() {
1721 let mut c = Complex::new(1.0, 2.0);
1722 c.multiply_real_part(&f64::NAN);
1723 }
1724
1725 #[test]
1726 fn multiply_imaginary_part() {
1727 let mut c = Complex::new(1.0, 2.0);
1728 c.multiply_imaginary_part(&3.0);
1729 assert_eq!(c.re, 1.0);
1730 assert_eq!(c.im, 6.0);
1731
1732 c.multiply_imaginary_part(&-0.5);
1733 assert_eq!(c.re, 1.0);
1734 assert_eq!(c.im, -3.0);
1735 }
1736
1737 #[cfg(debug_assertions)]
1738 #[test]
1739 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1740 fn multiply_imaginary_part_nan() {
1741 let mut c = Complex::new(1.0, 2.0);
1742 c.multiply_imaginary_part(&f64::NAN);
1743 }
1744
1745 #[test]
1746 fn set_real_part() {
1747 let mut c = Complex::new(1.0, 2.0);
1748 c.set_real_part(3.0);
1749 assert_eq!(c.re, 3.0);
1750 assert_eq!(c.im, 2.0);
1751
1752 c.set_real_part(-4.0);
1753 assert_eq!(c.re, -4.0);
1754 assert_eq!(c.im, 2.0);
1755 }
1756
1757 #[cfg(debug_assertions)]
1758 #[test]
1759 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1760 fn set_real_part_nan() {
1761 let mut c = Complex::new(1.0, 2.0);
1762 c.set_real_part(f64::NAN);
1763 }
1764
1765 #[test]
1766 fn set_imaginary_part() {
1767 let mut c = Complex::new(1.0, 2.0);
1768 c.set_imaginary_part(3.0);
1769 assert_eq!(c.re, 1.0);
1770 assert_eq!(c.im, 3.0);
1771
1772 c.set_imaginary_part(-4.0);
1773 assert_eq!(c.re, 1.0);
1774 assert_eq!(c.im, -4.0);
1775 }
1776
1777 #[cfg(debug_assertions)]
1778 #[test]
1779 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1780 fn set_imaginary_part_nan() {
1781 let mut c = Complex::new(1.0, 2.0);
1782 c.set_imaginary_part(f64::NAN);
1783 }
1784
1785 #[test]
1786 #[allow(clippy::op_ref)]
1787 fn multiply_ref() {
1788 let c1 = Complex::new(1.0, 2.0);
1789 let c2 = Complex::new(3.0, 4.0);
1790 let result = c1 * &c2;
1791 assert_eq!(result, Complex::new(-5.0, 10.0)); }
1793 }
1794}