1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
65 ComplexScalar, Constants, FpScalar, MulAddRef, RealScalar,
66 core::{
67 errors::{
68 ErrorsRawRealToInteger, ErrorsTryFromf64, ErrorsValidationRawComplex,
69 ErrorsValidationRawReal, capture_backtrace,
70 },
71 policies::{Native64RawRealStrictFinitePolicy, StrictFinitePolicy, validate_complex},
72 traits::{RawKernel, validation::ValidationPolicyReal},
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 RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow, RawScalarTrait,
83 RawScalarTrigonometric,
84 },
85 scalar_kind,
86};
87use az::CheckedAs;
88use duplicate::duplicate_item;
89use num::{Complex, Zero};
90use num_traits::{MulAdd, MulAddAssign};
91use std::{
92 cmp::Ordering,
93 hash::{Hash, Hasher},
94 num::FpCategory,
95};
96use try_create::ValidationPolicy;
97
98#[derive(Debug, Clone, PartialEq, PartialOrd)]
108pub struct Native64;
109
110impl RawKernel for Native64 {
111 type RawReal = f64;
113
114 type RawComplex = Complex<f64>;
116}
117
118impl FpScalar for f64 {
126 type Kind = scalar_kind::Real;
127
128 type RealType = f64;
130
131 fn as_raw_ref(&self) -> &Self::InnerType {
133 self
134 }
135}
136
137impl FpScalar for Complex<f64> {
142 type Kind = scalar_kind::Complex;
143
144 type RealType = f64;
146
147 fn as_raw_ref(&self) -> &Self::InnerType {
149 self
150 }
151}
152impl Sign for f64 {
156 #[inline(always)]
158 fn kernel_copysign(self, sign: &Self) -> Self {
159 self.copysign(*sign)
160 }
161
162 #[inline(always)]
164 fn kernel_is_sign_negative(&self) -> bool {
165 self.is_sign_negative()
166 }
167
168 #[inline(always)]
170 fn kernel_is_sign_positive(&self) -> bool {
171 self.is_sign_positive()
172 }
173
174 #[inline(always)]
181 fn kernel_signum(self) -> Self {
182 self.signum()
183 }
184}
185
186impl Rounding for f64 {
187 #[inline(always)]
189 fn kernel_ceil(self) -> Self {
190 self.ceil()
191 }
192
193 #[inline(always)]
195 fn kernel_floor(self) -> Self {
196 self.floor()
197 }
198
199 #[inline(always)]
201 fn kernel_fract(self) -> Self {
202 self.fract()
203 }
204
205 #[inline(always)]
207 fn kernel_round(self) -> Self {
208 self.round()
209 }
210
211 #[inline(always)]
230 fn kernel_round_ties_even(self) -> Self {
231 self.round_ties_even()
232 }
233
234 #[inline(always)]
249 fn kernel_trunc(self) -> Self {
250 self.trunc()
251 }
252}
253
254impl Constants for f64 {
255 #[inline(always)]
261 fn epsilon() -> Self {
262 f64::EPSILON
263 }
264
265 #[inline(always)]
267 fn negative_one() -> Self {
268 -1.
269 }
270
271 #[inline(always)]
273 fn one_div_2() -> Self {
274 0.5
275 }
276
277 #[inline(always)]
279 fn two() -> Self {
280 2.
281 }
282
283 #[inline(always)]
285 fn max_finite() -> Self {
286 f64::MAX
287 }
288
289 #[inline(always)]
291 fn min_finite() -> Self {
292 f64::MIN
293 }
294
295 #[inline(always)]
297 fn pi() -> Self {
298 std::f64::consts::PI
299 }
300
301 #[inline(always)]
303 fn two_pi() -> Self {
304 std::f64::consts::PI * 2.
305 }
306
307 #[inline(always)]
309 fn pi_div_2() -> Self {
310 std::f64::consts::FRAC_PI_2
311 }
312
313 #[inline(always)]
315 fn ln_2() -> Self {
316 std::f64::consts::LN_2
317 }
318
319 #[inline(always)]
321 fn ln_10() -> Self {
322 std::f64::consts::LN_10
323 }
324
325 #[inline(always)]
327 fn log10_2() -> Self {
328 std::f64::consts::LOG10_2
329 }
330
331 #[inline(always)]
333 fn log2_10() -> Self {
334 std::f64::consts::LOG2_10
335 }
336
337 #[inline(always)]
339 fn log2_e() -> Self {
340 std::f64::consts::LOG2_E
341 }
342
343 #[inline(always)]
345 fn log10_e() -> Self {
346 std::f64::consts::LOG10_E
347 }
348
349 #[inline(always)]
351 fn e() -> Self {
352 std::f64::consts::E
353 }
354}
355
356impl Clamp for f64 {
357 #[inline(always)]
375 fn clamp_ref(self, min: &Self, max: &Self) -> Self {
376 f64::clamp(self, *min, *max)
377 }
378}
379
380impl Classify for f64 {
381 #[inline(always)]
394 fn classify(&self) -> FpCategory {
395 f64::classify(*self)
396 }
397}
398
399impl ExpM1 for f64 {
400 #[inline(always)]
402 fn exp_m1(self) -> Self {
403 f64::exp_m1(self)
404 }
405}
406
407impl Hypot for f64 {
408 #[inline(always)]
411 fn hypot(self, other: &Self) -> Self {
412 f64::hypot(self, *other)
413 }
414}
415
416impl Ln1p for f64 {
417 #[inline(always)]
419 fn ln_1p(self) -> Self {
420 f64::ln_1p(self)
421 }
422}
423
424impl TotalCmp for f64 {
425 #[inline(always)]
426 fn total_cmp(&self, other: &Self) -> Ordering {
427 self.total_cmp(other)
428 }
429}
430
431impl RealScalar for f64 {
432 type RawReal = f64;
433
434 #[inline(always)]
437 fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
438 self.mul_add_assign(*mul, add_mul1 * add_mul2);
439 }
440
441 #[inline(always)]
444 fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
445 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
446 }
447
448 #[inline(always)]
452 fn try_from_f64(value: f64) -> Result<Self, ErrorsTryFromf64<f64>> {
453 StrictFinitePolicy::<f64, 53>::validate(value)
454 .map_err(|e| ErrorsTryFromf64::Output { source: e })
455 }
456}
457
458impl ComplexScalarConstructors for Complex<f64> {
459 type RawComplex = Complex<f64>;
460
461 fn try_new_complex(
462 real_part: f64,
463 imag_part: f64,
464 ) -> Result<Self, ErrorsValidationRawComplex<ErrorsValidationRawReal<f64>>> {
465 validate_complex::<Native64RawRealStrictFinitePolicy>(&real_part, &imag_part)
466 .map(|_| Complex::new(real_part, imag_part))
467 }
468}
469
470impl ComplexScalarGetParts for Complex<f64> {
472 #[inline(always)]
474 fn real_part(&self) -> f64 {
475 self.re
476 }
477
478 #[inline(always)]
480 fn imag_part(&self) -> f64 {
481 self.im
482 }
483
484 #[inline(always)]
486 fn raw_real_part(&self) -> &f64 {
487 &self.re
488 }
489
490 #[inline(always)]
492 fn raw_imag_part(&self) -> &f64 {
493 &self.im
494 }
495}
496
497impl ComplexScalarSetParts for Complex<f64> {
499 #[inline(always)]
505 fn set_real_part(&mut self, real_part: f64) {
506 debug_assert!(
507 real_part.is_finite(),
508 "The real part is not finite (i.e. is infinite or NaN)."
509 );
510 self.re = real_part;
511 }
512
513 #[inline(always)]
519 fn set_imaginary_part(&mut self, imag_part: f64) {
520 debug_assert!(
521 imag_part.is_finite(),
522 "The imaginary part is not finite (i.e. is infinite or NaN)."
523 );
524 self.im = imag_part;
525 }
526}
527
528impl ComplexScalarMutateParts for Complex<f64> {
530 #[inline(always)]
536 fn add_to_real_part(&mut self, c: &f64) {
537 self.re += c;
538
539 debug_assert!(
540 self.re.is_finite(),
541 "The real part is not finite (i.e. is infinite or NaN)."
542 );
543 }
544
545 #[inline(always)]
551 fn add_to_imaginary_part(&mut self, c: &f64) {
552 self.im += c;
553
554 debug_assert!(
555 self.im.is_finite(),
556 "The imaginary part is not finite (i.e. is infinite or NaN)."
557 );
558 }
559
560 #[inline(always)]
566 fn multiply_real_part(&mut self, c: &f64) {
567 self.re *= c;
568
569 debug_assert!(
570 self.re.is_finite(),
571 "The real part is not finite (i.e. is infinite or NaN)."
572 );
573 }
574
575 #[inline(always)]
581 fn multiply_imaginary_part(&mut self, c: &f64) {
582 self.im *= c;
583
584 debug_assert!(
585 self.im.is_finite(),
586 "The imaginary part is not finite (i.e. is infinite or NaN)."
587 );
588 }
589}
590
591impl ComplexScalar for Complex<f64> {
593 fn into_parts(self) -> (Self::RealType, Self::RealType) {
594 (self.re, self.im)
595 }
596}
597
598#[duplicate_item(
602 T trait_comment;
603 [f64] ["Implementation of the [`MulAddRef`] trait for `f64`."];
604 [Complex<f64>] ["Implementation of the [`MulAddRef`] trait for `Complex<f64>`."];
605)]
606#[doc = trait_comment]
607impl MulAddRef for T {
608 #[inline(always)]
612 fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
613 <Self as num::traits::MulAdd>::mul_add(self, *b, *c)
614 }
615}
616#[duplicate_item(
623 T;
624 [f64];
625 [Complex::<f64>];
626)]
627impl RawScalarTrigonometric for T {
628 #[duplicate_item(
629 unchecked_method method;
630 [unchecked_sin] [sin];
631 [unchecked_asin] [asin];
632 [unchecked_cos] [cos];
633 [unchecked_acos] [acos];
634 [unchecked_tan] [tan];
635 [unchecked_atan] [atan];
636 )]
637 #[inline(always)]
638 fn unchecked_method(self) -> Self {
639 T::method(self)
640 }
641}
642
643#[duplicate_item(
644 T;
645 [f64];
646 [Complex::<f64>];
647)]
648impl RawScalarHyperbolic for T {
649 #[duplicate_item(
650 unchecked_method method;
651 [unchecked_sinh] [sinh];
652 [unchecked_asinh] [asinh];
653 [unchecked_cosh] [cosh];
654 [unchecked_acosh] [acosh];
655 [unchecked_tanh] [tanh];
656 [unchecked_atanh] [atanh];
657 )]
658 #[inline(always)]
659 fn unchecked_method(self) -> Self {
660 T::method(self)
661 }
662}
663
664impl RawScalarPow for f64 {
665 #[duplicate_item(
666 unchecked_method exponent_type;
667 [unchecked_pow_exponent_i8] [i8];
668 [unchecked_pow_exponent_i16] [i16];
669 [unchecked_pow_exponent_u8] [u8];
670 [unchecked_pow_exponent_u16] [u16];
671 )]
672 #[inline(always)]
673 fn unchecked_method(self, exponent: &exponent_type) -> f64 {
674 f64::powi(self, (*exponent).into())
675 }
676
677 #[inline(always)]
678 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
679 f64::powi(self, *exponent)
680 }
681
682 #[duplicate_item(
683 unchecked_method exponent_type;
684 [unchecked_pow_exponent_i64] [i64];
685 [unchecked_pow_exponent_i128] [i128];
686 [unchecked_pow_exponent_isize] [isize];
687 [unchecked_pow_exponent_u32] [u32];
688 [unchecked_pow_exponent_u64] [u64];
689 [unchecked_pow_exponent_u128] [u128];
690 [unchecked_pow_exponent_usize] [usize];
691 )]
692 #[inline(always)]
693 fn unchecked_method(self, exponent: &exponent_type) -> f64 {
694 f64::powi(
695 self,
696 (*exponent)
697 .try_into()
698 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
699 )
700 }
701}
702
703impl RawScalarTrait for f64 {
704 type ValidationErrors = ErrorsValidationRawReal<f64>;
705
706 #[inline(always)]
707 fn raw_zero(_precision: u32) -> f64 {
708 0.
709 }
710
711 #[inline(always)]
712 fn is_zero(&self) -> bool {
713 <Self as Zero>::is_zero(self)
714 }
715 #[inline(always)]
716 fn raw_one(_precision: u32) -> f64 {
717 1.
718 }
719
720 #[duplicate_item(
721 unchecked_method method;
722 [unchecked_reciprocal] [recip];
723 [unchecked_exp] [exp];
724 [unchecked_sqrt] [sqrt];
725 [unchecked_ln] [ln];
726 [unchecked_log2] [log2];
727 [unchecked_log10] [log10];
728 )]
729 #[inline(always)]
730 fn unchecked_method(self) -> f64 {
731 f64::method(self)
732 }
733
734 #[inline(always)]
738 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
739 f64::mul_add(self, *b, *c)
740 }
741
742 #[inline(always)]
743 fn compute_hash<H: Hasher>(&self, state: &mut H) {
744 debug_assert!(
745 self.is_finite(),
746 "Hashing a non-finite f64 value (i.e., NaN or Infinity) may lead to inconsistent results."
747 );
748 if self == &0.0 {
749 0.0f64.to_bits().hash(state);
751 } else {
752 self.to_bits().hash(state);
753 }
754 }
755}
756
757impl RawRealTrait for f64 {
758 type RawComplex = Complex<f64>;
759
760 #[inline(always)]
761 fn unchecked_abs(self) -> f64 {
762 f64::abs(self)
763 }
764
765 #[inline(always)]
766 fn unchecked_atan2(self, denominator: &Self) -> Self {
767 f64::atan2(self, *denominator)
768 }
769
770 #[inline(always)]
771 fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
772 f64::powf(self, *exponent)
773 }
774
775 #[inline(always)]
776 fn unchecked_hypot(self, other: &Self) -> Self {
777 f64::hypot(self, *other)
778 }
779
780 #[inline(always)]
781 fn unchecked_ln_1p(self) -> Self {
782 f64::ln_1p(self)
783 }
784
785 #[inline(always)]
786 fn unchecked_exp_m1(self) -> Self {
787 f64::exp_m1(self)
788 }
789
790 #[inline(always)]
793 fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
794 self.mul_add_assign(*mul, add_mul1 * add_mul2);
795 }
796
797 #[inline(always)]
800 fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
801 self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
802 }
803
804 #[inline(always)]
805 fn raw_total_cmp(&self, other: &Self) -> Ordering {
806 f64::total_cmp(self, other)
807 }
808
809 #[inline(always)]
811 fn raw_clamp(self, min: &Self, max: &Self) -> Self {
812 f64::clamp(self, *min, *max)
813 }
814
815 #[inline(always)]
816 fn raw_classify(&self) -> FpCategory {
817 f64::classify(*self)
818 }
819
820 #[inline(always)]
821 fn raw_two(_precision: u32) -> Self {
822 2.
823 }
824
825 #[inline(always)]
826 fn raw_one_div_2(_precision: u32) -> Self {
827 0.5
828 }
829
830 #[inline(always)]
831 fn raw_pi(_precision: u32) -> Self {
832 std::f64::consts::PI
833 }
834
835 #[inline(always)]
836 fn raw_two_pi(_precision: u32) -> Self {
837 2. * std::f64::consts::PI
838 }
839
840 #[inline(always)]
841 fn raw_pi_div_2(_precision: u32) -> Self {
842 std::f64::consts::FRAC_PI_2
843 }
844
845 #[inline(always)]
846 fn raw_max_finite(_precision: u32) -> Self {
847 f64::MAX
848 }
849
850 #[inline(always)]
851 fn raw_min_finite(_precision: u32) -> Self {
852 f64::MIN
853 }
854
855 #[inline(always)]
856 fn raw_epsilon(_precision: u32) -> Self {
857 f64::EPSILON
858 }
859
860 #[inline(always)]
861 fn raw_ln_2(_precision: u32) -> Self {
862 std::f64::consts::LN_2
863 }
864
865 #[inline(always)]
866 fn raw_ln_10(_precision: u32) -> Self {
867 std::f64::consts::LN_10
868 }
869
870 #[inline(always)]
871 fn raw_log10_2(_precision: u32) -> Self {
872 std::f64::consts::LOG10_2
873 }
874
875 #[inline(always)]
876 fn raw_log2_10(_precision: u32) -> Self {
877 std::f64::consts::LOG2_10
878 }
879
880 #[inline(always)]
881 fn raw_log2_e(_precision: u32) -> Self {
882 std::f64::consts::LOG2_E
883 }
884
885 #[inline(always)]
886 fn raw_log10_e(_precision: u32) -> Self {
887 std::f64::consts::LOG10_E
888 }
889
890 #[inline(always)]
891 fn raw_e(_precision: u32) -> Self {
892 std::f64::consts::E
893 }
894
895 #[inline(always)]
896 fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
897 value: f64,
898 ) -> Result<Self, ErrorsTryFromf64<f64>> {
899 RealPolicy::validate(value).map_err(|e| ErrorsTryFromf64::Output { source: e })
900 }
901
902 #[inline(always)]
903 fn precision(&self) -> u32 {
904 53 }
906
907 #[inline(always)]
908 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<f64, usize>> {
909 if !self.is_finite() {
910 return Err(ErrorsRawRealToInteger::NotFinite {
911 value: self,
912 backtrace: capture_backtrace(),
913 });
914 }
915
916 match self.checked_as::<usize>() {
917 Some(value) => Ok(value),
918 None => Err(ErrorsRawRealToInteger::OutOfRange {
919 value: self,
920 min: usize::MIN,
921 max: usize::MAX,
922 backtrace: capture_backtrace(),
923 }),
924 }
925 }
926}
927
928impl RawScalarPow for Complex<f64> {
929 #[duplicate_item(
930 unchecked_method exponent_type;
931 [unchecked_pow_exponent_i8] [i8];
932 [unchecked_pow_exponent_i16] [i16];
933 )]
934 #[inline(always)]
935 fn unchecked_method(self, exponent: &exponent_type) -> Self {
936 Complex::<f64>::powi(&self, (*exponent).into())
937 }
938
939 #[inline(always)]
940 fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
941 Complex::<f64>::powi(&self, *exponent)
942 }
943
944 #[duplicate_item(
945 unchecked_method exponent_type;
946 [unchecked_pow_exponent_i64] [i64];
947 [unchecked_pow_exponent_i128] [i128];
948 [unchecked_pow_exponent_isize] [isize];
949 )]
950 #[inline(always)]
951 fn unchecked_method(self, exponent: &exponent_type) -> Self {
952 Complex::<f64>::powi(
953 &self,
954 (*exponent)
955 .try_into()
956 .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
957 )
958 }
959
960 #[duplicate_item(
961 unchecked_method exponent_type;
962 [unchecked_pow_exponent_u8] [u8];
963 [unchecked_pow_exponent_u16] [u16];
964 )]
965 #[inline(always)]
966 fn unchecked_method(self, exponent: &exponent_type) -> Self {
967 Complex::<f64>::powu(&self, (*exponent).into())
968 }
969
970 #[inline(always)]
971 fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
972 Complex::<f64>::powu(&self, *exponent)
973 }
974
975 #[duplicate_item(
976 unchecked_method exponent_type;
977 [unchecked_pow_exponent_u64] [u64];
978 [unchecked_pow_exponent_u128] [u128];
979 [unchecked_pow_exponent_usize] [usize];
980 )]
981 #[inline(always)]
982 fn unchecked_method(self, exponent: &exponent_type) -> Self {
983 Complex::<f64>::powu(
984 &self,
985 (*exponent)
986 .try_into()
987 .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
988 )
989 }
990}
991
992impl RawScalarTrait for Complex<f64> {
993 type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<f64>>;
994
995 #[inline(always)]
996 fn raw_zero(_precision: u32) -> Self {
997 Complex::new(0., 0.)
998 }
999
1000 #[inline(always)]
1001 fn is_zero(&self) -> bool {
1002 <Self as Zero>::is_zero(self)
1003 }
1004
1005 #[inline(always)]
1006 fn raw_one(_precision: u32) -> Self {
1007 Complex::new(1., 0.)
1008 }
1009
1010 #[duplicate_item(
1011 unchecked_method method;
1012 [unchecked_exp] [exp];
1013 [unchecked_sqrt] [sqrt];
1014 [unchecked_ln] [ln];
1015 [unchecked_log10] [log10];
1016 )]
1017 #[inline(always)]
1018 fn unchecked_method(self) -> Self {
1019 Complex::<f64>::method(self)
1020 }
1021
1022 #[inline(always)]
1023 fn unchecked_reciprocal(self) -> Self {
1024 Complex::<f64>::inv(&self)
1025 }
1026
1027 #[inline(always)]
1028 fn unchecked_log2(self) -> Self {
1029 Complex::<f64>::ln(self) / std::f64::consts::LN_2
1030 }
1031
1032 #[inline(always)]
1036 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
1037 Complex::<f64>::mul_add(self, *b, *c)
1038 }
1039
1040 fn compute_hash<H: Hasher>(&self, state: &mut H) {
1041 RawComplexTrait::raw_real_part(self).compute_hash(state);
1042 RawComplexTrait::raw_imag_part(self).compute_hash(state);
1043 }
1044}
1045
1046impl RawComplexTrait for Complex<f64> {
1047 type RawReal = f64;
1048
1049 fn new_unchecked_raw_complex(real: f64, imag: f64) -> Self {
1050 Complex::<f64>::new(real, imag)
1051 }
1052
1053 fn mut_raw_real_part(&mut self) -> &mut f64 {
1055 &mut self.re
1056 }
1057
1058 fn mut_raw_imag_part(&mut self) -> &mut f64 {
1060 &mut self.im
1061 }
1062
1063 #[inline(always)]
1064 fn unchecked_abs(self) -> f64 {
1065 Complex::<f64>::norm(self)
1066 }
1067
1068 #[inline(always)]
1069 fn raw_real_part(&self) -> &f64 {
1070 &self.re
1071 }
1072
1073 #[inline(always)]
1074 fn raw_imag_part(&self) -> &f64 {
1075 &self.im
1076 }
1077
1078 #[inline(always)]
1079 fn unchecked_arg(self) -> f64 {
1080 Complex::<f64>::arg(self)
1081 }
1082
1083 #[inline(always)]
1084 fn unchecked_pow_exponent_real(self, exponent: &f64) -> Self {
1085 Complex::<f64>::powf(self, *exponent)
1086 }
1087}
1088
1089#[cfg(test)]
1090mod tests {
1091 use crate::{
1092 core::errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal},
1093 functions::TotalCmp,
1094 };
1095
1096 mod real {
1097 use super::*;
1098 use crate::Constants;
1099
1100 #[test]
1101 fn test_constants() {
1102 assert_eq!(<f64 as Constants>::epsilon(), f64::EPSILON);
1103 assert_eq!(<f64 as Constants>::negative_one(), -1.0);
1104 assert_eq!(<f64 as Constants>::one_div_2(), 0.5);
1105 assert_eq!(<f64 as Constants>::two(), 2.0);
1106 assert_eq!(<f64 as Constants>::max_finite(), f64::MAX);
1107 assert_eq!(<f64 as Constants>::min_finite(), f64::MIN);
1108 assert_eq!(<f64 as Constants>::pi(), std::f64::consts::PI);
1109 assert_eq!(<f64 as Constants>::two_pi(), std::f64::consts::PI * 2.0);
1110 assert_eq!(<f64 as Constants>::pi_div_2(), std::f64::consts::FRAC_PI_2);
1111 assert_eq!(<f64 as Constants>::ln_2(), std::f64::consts::LN_2);
1112 assert_eq!(<f64 as Constants>::ln_10(), std::f64::consts::LN_10);
1113 assert_eq!(<f64 as Constants>::log10_2(), std::f64::consts::LOG10_2);
1114 assert_eq!(<f64 as Constants>::log2_10(), std::f64::consts::LOG2_10);
1115 assert_eq!(<f64 as Constants>::log2_e(), std::f64::consts::LOG2_E);
1116 assert_eq!(<f64 as Constants>::log10_e(), std::f64::consts::LOG10_E);
1117 assert_eq!(<f64 as Constants>::e(), std::f64::consts::E);
1118 }
1119
1120 #[test]
1121 #[allow(clippy::op_ref)]
1122 fn multiply_ref() {
1123 let a = 2.0f64;
1124 let b = 3.0f64;
1125 let result = a * &b;
1126 assert_eq!(result, 6.0);
1127 }
1128
1129 #[test]
1130 fn total_cmp() {
1131 let a = 2.0f64;
1132 let b = 3.0f64;
1133 assert_eq!(
1134 <f64 as TotalCmp>::total_cmp(&a, &b),
1135 std::cmp::Ordering::Less
1136 );
1137 assert_eq!(
1138 <f64 as TotalCmp>::total_cmp(&b, &a),
1139 std::cmp::Ordering::Greater
1140 );
1141 assert_eq!(
1142 <f64 as TotalCmp>::total_cmp(&a, &a),
1143 std::cmp::Ordering::Equal
1144 );
1145 }
1146
1147 mod from_f64 {
1148 use crate::{RealScalar, backends::native64::validated::RealNative64StrictFinite};
1149
1150 #[test]
1151 fn test_from_f64_valid_constants() {
1152 let pi = RealNative64StrictFinite::from_f64(std::f64::consts::PI);
1154 assert_eq!(pi.as_ref(), &std::f64::consts::PI);
1155
1156 let e = RealNative64StrictFinite::from_f64(std::f64::consts::E);
1157 assert_eq!(e.as_ref(), &std::f64::consts::E);
1158
1159 let sqrt2 = RealNative64StrictFinite::from_f64(std::f64::consts::SQRT_2);
1160 assert_eq!(sqrt2.as_ref(), &std::f64::consts::SQRT_2);
1161 }
1162
1163 #[test]
1164 fn test_from_f64_valid_values() {
1165 let x = RealNative64StrictFinite::from_f64(42.0);
1167 assert_eq!(x.as_ref(), &42.0);
1168
1169 let y = RealNative64StrictFinite::from_f64(-3.0);
1170 assert_eq!(y.as_ref(), &-3.0);
1171
1172 let z = RealNative64StrictFinite::from_f64(0.0);
1173 assert_eq!(z.as_ref(), &0.0);
1174 }
1175
1176 #[test]
1177 #[should_panic(expected = "RealScalar::from_f64() failed")]
1178 fn test_from_f64_nan_panics() {
1179 let _ = RealNative64StrictFinite::from_f64(f64::NAN);
1180 }
1181
1182 #[test]
1183 #[should_panic(expected = "RealScalar::from_f64() failed")]
1184 fn test_from_f64_infinity_panics() {
1185 let _ = RealNative64StrictFinite::from_f64(f64::INFINITY);
1186 }
1187
1188 #[test]
1189 #[should_panic(expected = "RealScalar::from_f64() failed")]
1190 fn test_from_f64_neg_infinity_panics() {
1191 let _ = RealNative64StrictFinite::from_f64(f64::NEG_INFINITY);
1192 }
1193
1194 #[test]
1195 #[should_panic(expected = "RealScalar::from_f64() failed")]
1196 fn test_from_f64_subnormal_panics() {
1197 let _ = RealNative64StrictFinite::from_f64(f64::MIN_POSITIVE / 2.0);
1199 }
1200
1201 #[test]
1202 fn test_try_from_f64_error_handling() {
1203 assert!(RealNative64StrictFinite::try_from_f64(f64::NAN).is_err());
1205 assert!(RealNative64StrictFinite::try_from_f64(f64::INFINITY).is_err());
1206 assert!(RealNative64StrictFinite::try_from_f64(f64::NEG_INFINITY).is_err());
1207
1208 assert!(RealNative64StrictFinite::try_from_f64(3.0).is_ok());
1210 assert!(RealNative64StrictFinite::try_from_f64(0.0).is_ok());
1211 }
1212 }
1213
1214 mod truncate_to_usize {
1215 use crate::{core::errors::ErrorsRawRealToInteger, kernels::RawRealTrait};
1216
1217 #[test]
1218 fn test_f64_truncate_to_usize_valid() {
1219 assert_eq!(42.0_f64.truncate_to_usize().unwrap(), 42);
1220 assert_eq!(42.9_f64.truncate_to_usize().unwrap(), 42);
1221 assert_eq!(0.0_f64.truncate_to_usize().unwrap(), 0);
1222 }
1223
1224 #[test]
1225 fn test_f64_truncate_to_usize_not_finite() {
1226 assert!(matches!(
1227 f64::NAN.truncate_to_usize(),
1228 Err(ErrorsRawRealToInteger::NotFinite { .. })
1229 ));
1230 assert!(matches!(
1231 f64::INFINITY.truncate_to_usize(),
1232 Err(ErrorsRawRealToInteger::NotFinite { .. })
1233 ));
1234 assert!(matches!(
1235 f64::NEG_INFINITY.truncate_to_usize(),
1236 Err(ErrorsRawRealToInteger::NotFinite { .. })
1237 ));
1238 }
1239
1240 #[test]
1241 fn test_f64_truncate_to_usize_out_of_range() {
1242 assert!(matches!(
1244 (-1.0_f64).truncate_to_usize(),
1245 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1246 ));
1247 assert!(matches!(
1249 ((usize::MAX as f64) + 1.0).truncate_to_usize(),
1250 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1251 ));
1252
1253 assert!(matches!(
1255 (usize::MAX as f64).truncate_to_usize(),
1256 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1257 ));
1258 }
1259 }
1260 }
1261
1262 mod complex {
1263 use super::*;
1264 use crate::{
1265 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
1266 ComplexScalarSetParts,
1267 };
1268 use num::{Complex, Zero};
1269
1270 #[test]
1271 fn real_part() {
1272 let c1 = Complex::new(1.23, 4.56);
1273 assert_eq!(c1.real_part(), 1.23);
1274
1275 let c2 = Complex::new(-7.89, 0.12);
1276 assert_eq!(c2.real_part(), -7.89);
1277
1278 let c3 = Complex::new(0.0, 10.0);
1279 assert_eq!(c3.real_part(), 0.0);
1280
1281 let c_nan_re = Complex::new(f64::NAN, 5.0);
1282 assert!(c_nan_re.real_part().is_nan());
1283
1284 let c_inf_re = Complex::new(f64::INFINITY, 5.0);
1285 assert!(c_inf_re.real_part().is_infinite());
1286 assert!(c_inf_re.real_part().is_sign_positive());
1287
1288 let c_neg_inf_re = Complex::new(f64::NEG_INFINITY, 5.0);
1289 assert!(c_neg_inf_re.real_part().is_infinite());
1290 assert!(c_neg_inf_re.real_part().is_sign_negative());
1291 }
1292
1293 #[test]
1294 fn imag_part() {
1295 let c1 = Complex::new(1.23, 4.56);
1296 assert_eq!(c1.imag_part(), 4.56);
1297
1298 let c2 = Complex::new(7.89, -0.12);
1299 assert_eq!(c2.imag_part(), -0.12);
1300
1301 let c3 = Complex::new(10.0, 0.0);
1302 assert_eq!(c3.imag_part(), 0.0);
1303
1304 let c_nan_im = Complex::new(5.0, f64::NAN);
1305 assert!(c_nan_im.imag_part().is_nan());
1306
1307 let c_inf_im = Complex::new(5.0, f64::INFINITY);
1308 assert!(c_inf_im.imag_part().is_infinite());
1309 assert!(c_inf_im.imag_part().is_sign_positive());
1310
1311 let c_neg_inf_im = Complex::new(5.0, f64::NEG_INFINITY);
1312 assert!(c_neg_inf_im.imag_part().is_infinite());
1313 assert!(c_neg_inf_im.imag_part().is_sign_negative());
1314 }
1315
1316 #[test]
1317 fn try_new_complex() {
1318 let r1 = 1.23;
1319 let i1 = 4.56;
1320 let c1 = Complex::<f64>::try_new_complex(r1, i1).unwrap();
1321 assert_eq!(c1.re, r1);
1322 assert_eq!(c1.im, i1);
1323 assert_eq!(c1.real_part(), r1);
1324 assert_eq!(c1.imag_part(), i1);
1325
1326 let r2 = -7.89;
1327 let i2 = -0.12;
1328 let c2 = Complex::<f64>::try_new_complex(r2, i2).unwrap();
1329 assert_eq!(c2.re, r2);
1330 assert_eq!(c2.im, i2);
1331 assert_eq!(c2.real_part(), r2);
1332 assert_eq!(c2.imag_part(), i2);
1333
1334 let r3 = 0.0;
1335 let i3 = 0.0;
1336 let c3 = Complex::<f64>::try_new_complex(r3, i3).unwrap();
1337 assert_eq!(c3.re, r3);
1338 assert_eq!(c3.im, i3);
1339 assert!(c3.is_zero()); let c_nan_re = Complex::<f64>::try_new_complex(f64::NAN, 5.0).unwrap_err();
1342 assert!(matches!(
1343 c_nan_re,
1344 ErrorsValidationRawComplex::InvalidRealPart { .. }
1345 ));
1346
1347 let c_inf_im = Complex::<f64>::try_new_complex(10.0, f64::INFINITY).unwrap_err();
1348 assert!(matches!(
1349 c_inf_im,
1350 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1351 ));
1352
1353 let c_nan_re_inf_im =
1354 Complex::<f64>::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
1355 assert!(matches!(
1356 c_nan_re_inf_im,
1357 ErrorsValidationRawComplex::InvalidBothParts { .. }
1358 ));
1359 }
1360
1361 #[test]
1362 fn try_new_pure_real() {
1363 let r1 = 1.23;
1364 let c1 = Complex::<f64>::try_new_pure_real(r1).unwrap();
1365 assert_eq!(c1.re, r1);
1366 assert_eq!(c1.im, 0.0);
1367
1368 let c_nan = Complex::<f64>::try_new_pure_real(f64::NAN).unwrap_err();
1369 assert!(matches!(
1370 c_nan,
1371 ErrorsValidationRawComplex::InvalidRealPart {
1372 source: ErrorsValidationRawReal::IsNaN { .. }
1373 }
1374 ));
1375 }
1376
1377 #[test]
1378 fn try_new_pure_imaginary() {
1379 let i1 = 1.23;
1380 let c1 = Complex::<f64>::try_new_pure_imaginary(i1).unwrap();
1381 assert_eq!(c1.re, 0.0);
1382 assert_eq!(c1.im, i1);
1383
1384 let c_nan = Complex::<f64>::try_new_pure_imaginary(f64::NAN).unwrap_err();
1385 assert!(matches!(
1386 c_nan,
1387 ErrorsValidationRawComplex::InvalidImaginaryPart {
1388 source: ErrorsValidationRawReal::IsNaN { .. }
1389 }
1390 ));
1391 }
1392
1393 #[test]
1394 fn add_to_real_part() {
1395 let mut c = Complex::new(1.0, 2.0);
1396 c.add_to_real_part(&3.0);
1397 assert_eq!(c.re, 4.0);
1398 assert_eq!(c.im, 2.0);
1399
1400 c.add_to_real_part(&-5.0);
1401 assert_eq!(c.re, -1.0);
1402 assert_eq!(c.im, 2.0);
1403 }
1404
1405 #[cfg(debug_assertions)]
1406 #[test]
1407 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1408 fn add_to_real_part_nan() {
1409 let mut c = Complex::new(1.0, 2.0);
1410 c.add_to_real_part(&f64::NAN);
1411 }
1412
1413 #[test]
1414 fn add_to_imaginary_part() {
1415 let mut c = Complex::new(1.0, 2.0);
1416 c.add_to_imaginary_part(&3.0);
1417 assert_eq!(c.re, 1.0);
1418 assert_eq!(c.im, 5.0);
1419
1420 c.add_to_imaginary_part(&-4.0);
1421 assert_eq!(c.re, 1.0);
1422 assert_eq!(c.im, 1.0);
1423 }
1424
1425 #[cfg(debug_assertions)]
1426 #[test]
1427 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1428 fn add_to_imaginary_part_nan() {
1429 let mut c = Complex::new(1.0, 2.0);
1430 c.add_to_imaginary_part(&f64::NAN);
1431 }
1432
1433 #[test]
1434 fn multiply_real_part() {
1435 let mut c = Complex::new(1.0, 2.0);
1436 c.multiply_real_part(&3.0);
1437 assert_eq!(c.re, 3.0);
1438 assert_eq!(c.im, 2.0);
1439
1440 c.multiply_real_part(&-2.0);
1441 assert_eq!(c.re, -6.0);
1442 assert_eq!(c.im, 2.0);
1443 }
1444
1445 #[cfg(debug_assertions)]
1446 #[test]
1447 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1448 fn multiply_real_part_nan() {
1449 let mut c = Complex::new(1.0, 2.0);
1450 c.multiply_real_part(&f64::NAN);
1451 }
1452
1453 #[test]
1454 fn multiply_imaginary_part() {
1455 let mut c = Complex::new(1.0, 2.0);
1456 c.multiply_imaginary_part(&3.0);
1457 assert_eq!(c.re, 1.0);
1458 assert_eq!(c.im, 6.0);
1459
1460 c.multiply_imaginary_part(&-0.5);
1461 assert_eq!(c.re, 1.0);
1462 assert_eq!(c.im, -3.0);
1463 }
1464
1465 #[cfg(debug_assertions)]
1466 #[test]
1467 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1468 fn multiply_imaginary_part_nan() {
1469 let mut c = Complex::new(1.0, 2.0);
1470 c.multiply_imaginary_part(&f64::NAN);
1471 }
1472
1473 #[test]
1474 fn set_real_part() {
1475 let mut c = Complex::new(1.0, 2.0);
1476 c.set_real_part(3.0);
1477 assert_eq!(c.re, 3.0);
1478 assert_eq!(c.im, 2.0);
1479
1480 c.set_real_part(-4.0);
1481 assert_eq!(c.re, -4.0);
1482 assert_eq!(c.im, 2.0);
1483 }
1484
1485 #[cfg(debug_assertions)]
1486 #[test]
1487 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1488 fn set_real_part_nan() {
1489 let mut c = Complex::new(1.0, 2.0);
1490 c.set_real_part(f64::NAN);
1491 }
1492
1493 #[test]
1494 fn set_imaginary_part() {
1495 let mut c = Complex::new(1.0, 2.0);
1496 c.set_imaginary_part(3.0);
1497 assert_eq!(c.re, 1.0);
1498 assert_eq!(c.im, 3.0);
1499
1500 c.set_imaginary_part(-4.0);
1501 assert_eq!(c.re, 1.0);
1502 assert_eq!(c.im, -4.0);
1503 }
1504
1505 #[cfg(debug_assertions)]
1506 #[test]
1507 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1508 fn set_imaginary_part_nan() {
1509 let mut c = Complex::new(1.0, 2.0);
1510 c.set_imaginary_part(f64::NAN);
1511 }
1512
1513 #[test]
1514 #[allow(clippy::op_ref)]
1515 fn multiply_ref() {
1516 let c1 = Complex::new(1.0, 2.0);
1517 let c2 = Complex::new(3.0, 4.0);
1518 let result = c1 * &c2;
1519 assert_eq!(result, Complex::new(-5.0, 10.0)); }
1521 }
1522}