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 use std::assert_matches;
1096
1097 mod real {
1098 use super::*;
1099 use crate::Constants;
1100
1101 #[test]
1102 fn test_constants() {
1103 assert_eq!(<f64 as Constants>::epsilon(), f64::EPSILON);
1104 assert_eq!(<f64 as Constants>::negative_one(), -1.0);
1105 assert_eq!(<f64 as Constants>::one_div_2(), 0.5);
1106 assert_eq!(<f64 as Constants>::two(), 2.0);
1107 assert_eq!(<f64 as Constants>::max_finite(), f64::MAX);
1108 assert_eq!(<f64 as Constants>::min_finite(), f64::MIN);
1109 assert_eq!(<f64 as Constants>::pi(), std::f64::consts::PI);
1110 assert_eq!(<f64 as Constants>::two_pi(), std::f64::consts::PI * 2.0);
1111 assert_eq!(<f64 as Constants>::pi_div_2(), std::f64::consts::FRAC_PI_2);
1112 assert_eq!(<f64 as Constants>::ln_2(), std::f64::consts::LN_2);
1113 assert_eq!(<f64 as Constants>::ln_10(), std::f64::consts::LN_10);
1114 assert_eq!(<f64 as Constants>::log10_2(), std::f64::consts::LOG10_2);
1115 assert_eq!(<f64 as Constants>::log2_10(), std::f64::consts::LOG2_10);
1116 assert_eq!(<f64 as Constants>::log2_e(), std::f64::consts::LOG2_E);
1117 assert_eq!(<f64 as Constants>::log10_e(), std::f64::consts::LOG10_E);
1118 assert_eq!(<f64 as Constants>::e(), std::f64::consts::E);
1119 }
1120
1121 #[test]
1122 #[allow(clippy::op_ref)]
1123 fn multiply_ref() {
1124 let a = 2.0f64;
1125 let b = 3.0f64;
1126 let result = a * &b;
1127 assert_eq!(result, 6.0);
1128 }
1129
1130 #[test]
1131 fn total_cmp() {
1132 let a = 2.0f64;
1133 let b = 3.0f64;
1134 assert_eq!(
1135 <f64 as TotalCmp>::total_cmp(&a, &b),
1136 std::cmp::Ordering::Less
1137 );
1138 assert_eq!(
1139 <f64 as TotalCmp>::total_cmp(&b, &a),
1140 std::cmp::Ordering::Greater
1141 );
1142 assert_eq!(
1143 <f64 as TotalCmp>::total_cmp(&a, &a),
1144 std::cmp::Ordering::Equal
1145 );
1146 }
1147
1148 mod from_f64 {
1149 use crate::{RealScalar, backends::native64::validated::RealNative64StrictFinite};
1150
1151 #[test]
1152 fn test_from_f64_valid_constants() {
1153 let pi = RealNative64StrictFinite::from_f64(std::f64::consts::PI);
1155 assert_eq!(pi.as_ref(), &std::f64::consts::PI);
1156
1157 let e = RealNative64StrictFinite::from_f64(std::f64::consts::E);
1158 assert_eq!(e.as_ref(), &std::f64::consts::E);
1159
1160 let sqrt2 = RealNative64StrictFinite::from_f64(std::f64::consts::SQRT_2);
1161 assert_eq!(sqrt2.as_ref(), &std::f64::consts::SQRT_2);
1162 }
1163
1164 #[test]
1165 fn test_from_f64_valid_values() {
1166 let x = RealNative64StrictFinite::from_f64(42.0);
1168 assert_eq!(x.as_ref(), &42.0);
1169
1170 let y = RealNative64StrictFinite::from_f64(-3.0);
1171 assert_eq!(y.as_ref(), &-3.0);
1172
1173 let z = RealNative64StrictFinite::from_f64(0.0);
1174 assert_eq!(z.as_ref(), &0.0);
1175 }
1176
1177 #[test]
1178 #[should_panic(expected = "RealScalar::from_f64() failed")]
1179 fn test_from_f64_nan_panics() {
1180 let _ = RealNative64StrictFinite::from_f64(f64::NAN);
1181 }
1182
1183 #[test]
1184 #[should_panic(expected = "RealScalar::from_f64() failed")]
1185 fn test_from_f64_infinity_panics() {
1186 let _ = RealNative64StrictFinite::from_f64(f64::INFINITY);
1187 }
1188
1189 #[test]
1190 #[should_panic(expected = "RealScalar::from_f64() failed")]
1191 fn test_from_f64_neg_infinity_panics() {
1192 let _ = RealNative64StrictFinite::from_f64(f64::NEG_INFINITY);
1193 }
1194
1195 #[test]
1196 #[should_panic(expected = "RealScalar::from_f64() failed")]
1197 fn test_from_f64_subnormal_panics() {
1198 let _ = RealNative64StrictFinite::from_f64(f64::MIN_POSITIVE / 2.0);
1200 }
1201
1202 #[test]
1203 fn test_try_from_f64_error_handling() {
1204 assert!(RealNative64StrictFinite::try_from_f64(f64::NAN).is_err());
1206 assert!(RealNative64StrictFinite::try_from_f64(f64::INFINITY).is_err());
1207 assert!(RealNative64StrictFinite::try_from_f64(f64::NEG_INFINITY).is_err());
1208
1209 assert!(RealNative64StrictFinite::try_from_f64(3.0).is_ok());
1211 assert!(RealNative64StrictFinite::try_from_f64(0.0).is_ok());
1212 }
1213 }
1214
1215 mod truncate_to_usize {
1216 use crate::{core::errors::ErrorsRawRealToInteger, kernels::RawRealTrait};
1217
1218 #[test]
1219 fn test_f64_truncate_to_usize_valid() {
1220 assert_eq!(42.0_f64.truncate_to_usize().unwrap(), 42);
1221 assert_eq!(42.9_f64.truncate_to_usize().unwrap(), 42);
1222 assert_eq!(0.0_f64.truncate_to_usize().unwrap(), 0);
1223 }
1224
1225 #[test]
1226 fn test_f64_truncate_to_usize_not_finite() {
1227 assert!(matches!(
1228 f64::NAN.truncate_to_usize(),
1229 Err(ErrorsRawRealToInteger::NotFinite { .. })
1230 ));
1231 assert!(matches!(
1232 f64::INFINITY.truncate_to_usize(),
1233 Err(ErrorsRawRealToInteger::NotFinite { .. })
1234 ));
1235 assert!(matches!(
1236 f64::NEG_INFINITY.truncate_to_usize(),
1237 Err(ErrorsRawRealToInteger::NotFinite { .. })
1238 ));
1239 }
1240
1241 #[test]
1242 fn test_f64_truncate_to_usize_out_of_range() {
1243 assert!(matches!(
1245 (-1.0_f64).truncate_to_usize(),
1246 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1247 ));
1248 assert!(matches!(
1250 ((usize::MAX as f64) + 1.0).truncate_to_usize(),
1251 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1252 ));
1253
1254 assert!(matches!(
1256 (usize::MAX as f64).truncate_to_usize(),
1257 Err(ErrorsRawRealToInteger::OutOfRange { .. })
1258 ));
1259 }
1260 }
1261 }
1262
1263 mod complex {
1264 use super::*;
1265 use crate::{
1266 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
1267 ComplexScalarSetParts,
1268 };
1269 use num::{Complex, Zero};
1270
1271 #[test]
1272 fn real_part() {
1273 let c1 = Complex::new(1.23, 4.56);
1274 assert_eq!(c1.real_part(), 1.23);
1275
1276 let c2 = Complex::new(-7.89, 0.12);
1277 assert_eq!(c2.real_part(), -7.89);
1278
1279 let c3 = Complex::new(0.0, 10.0);
1280 assert_eq!(c3.real_part(), 0.0);
1281
1282 let c_nan_re = Complex::new(f64::NAN, 5.0);
1283 assert!(c_nan_re.real_part().is_nan());
1284
1285 let c_inf_re = Complex::new(f64::INFINITY, 5.0);
1286 assert!(c_inf_re.real_part().is_infinite());
1287 assert!(c_inf_re.real_part().is_sign_positive());
1288
1289 let c_neg_inf_re = Complex::new(f64::NEG_INFINITY, 5.0);
1290 assert!(c_neg_inf_re.real_part().is_infinite());
1291 assert!(c_neg_inf_re.real_part().is_sign_negative());
1292 }
1293
1294 #[test]
1295 fn imag_part() {
1296 let c1 = Complex::new(1.23, 4.56);
1297 assert_eq!(c1.imag_part(), 4.56);
1298
1299 let c2 = Complex::new(7.89, -0.12);
1300 assert_eq!(c2.imag_part(), -0.12);
1301
1302 let c3 = Complex::new(10.0, 0.0);
1303 assert_eq!(c3.imag_part(), 0.0);
1304
1305 let c_nan_im = Complex::new(5.0, f64::NAN);
1306 assert!(c_nan_im.imag_part().is_nan());
1307
1308 let c_inf_im = Complex::new(5.0, f64::INFINITY);
1309 assert!(c_inf_im.imag_part().is_infinite());
1310 assert!(c_inf_im.imag_part().is_sign_positive());
1311
1312 let c_neg_inf_im = Complex::new(5.0, f64::NEG_INFINITY);
1313 assert!(c_neg_inf_im.imag_part().is_infinite());
1314 assert!(c_neg_inf_im.imag_part().is_sign_negative());
1315 }
1316
1317 #[test]
1318 fn try_new_complex() {
1319 let r1 = 1.23;
1320 let i1 = 4.56;
1321 let c1 = Complex::<f64>::try_new_complex(r1, i1).unwrap();
1322 assert_eq!(c1.re, r1);
1323 assert_eq!(c1.im, i1);
1324 assert_eq!(c1.real_part(), r1);
1325 assert_eq!(c1.imag_part(), i1);
1326
1327 let r2 = -7.89;
1328 let i2 = -0.12;
1329 let c2 = Complex::<f64>::try_new_complex(r2, i2).unwrap();
1330 assert_eq!(c2.re, r2);
1331 assert_eq!(c2.im, i2);
1332 assert_eq!(c2.real_part(), r2);
1333 assert_eq!(c2.imag_part(), i2);
1334
1335 let r3 = 0.0;
1336 let i3 = 0.0;
1337 let c3 = Complex::<f64>::try_new_complex(r3, i3).unwrap();
1338 assert_eq!(c3.re, r3);
1339 assert_eq!(c3.im, i3);
1340 assert!(c3.is_zero()); let c_nan_re = Complex::<f64>::try_new_complex(f64::NAN, 5.0).unwrap_err();
1343 assert!(matches!(
1344 c_nan_re,
1345 ErrorsValidationRawComplex::InvalidRealPart { .. }
1346 ));
1347
1348 let c_inf_im = Complex::<f64>::try_new_complex(10.0, f64::INFINITY).unwrap_err();
1349 assert!(matches!(
1350 c_inf_im,
1351 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1352 ));
1353
1354 let c_nan_re_inf_im =
1355 Complex::<f64>::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
1356 assert!(matches!(
1357 c_nan_re_inf_im,
1358 ErrorsValidationRawComplex::InvalidBothParts { .. }
1359 ));
1360 }
1361
1362 #[test]
1363 fn try_new_pure_real() {
1364 let r1 = 1.23;
1365 let c1 = Complex::<f64>::try_new_pure_real(r1).unwrap();
1366 assert_eq!(c1.re, r1);
1367 assert_eq!(c1.im, 0.0);
1368
1369 let c_nan = Complex::<f64>::try_new_pure_real(f64::NAN).unwrap_err();
1370 assert_matches!(
1371 c_nan,
1372 ErrorsValidationRawComplex::InvalidRealPart {
1373 source
1374 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1375 );
1376 }
1377
1378 #[test]
1379 fn try_new_pure_imaginary() {
1380 let i1 = 1.23;
1381 let c1 = Complex::<f64>::try_new_pure_imaginary(i1).unwrap();
1382 assert_eq!(c1.re, 0.0);
1383 assert_eq!(c1.im, i1);
1384
1385 let c_nan = Complex::<f64>::try_new_pure_imaginary(f64::NAN).unwrap_err();
1386 assert_matches!(
1387 c_nan,
1388 ErrorsValidationRawComplex::InvalidImaginaryPart {
1389 source
1390 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1391 );
1392 }
1393
1394 #[test]
1395 fn add_to_real_part() {
1396 let mut c = Complex::new(1.0, 2.0);
1397 c.add_to_real_part(&3.0);
1398 assert_eq!(c.re, 4.0);
1399 assert_eq!(c.im, 2.0);
1400
1401 c.add_to_real_part(&-5.0);
1402 assert_eq!(c.re, -1.0);
1403 assert_eq!(c.im, 2.0);
1404 }
1405
1406 #[cfg(debug_assertions)]
1407 #[test]
1408 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1409 fn add_to_real_part_nan() {
1410 let mut c = Complex::new(1.0, 2.0);
1411 c.add_to_real_part(&f64::NAN);
1412 }
1413
1414 #[test]
1415 fn add_to_imaginary_part() {
1416 let mut c = Complex::new(1.0, 2.0);
1417 c.add_to_imaginary_part(&3.0);
1418 assert_eq!(c.re, 1.0);
1419 assert_eq!(c.im, 5.0);
1420
1421 c.add_to_imaginary_part(&-4.0);
1422 assert_eq!(c.re, 1.0);
1423 assert_eq!(c.im, 1.0);
1424 }
1425
1426 #[cfg(debug_assertions)]
1427 #[test]
1428 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1429 fn add_to_imaginary_part_nan() {
1430 let mut c = Complex::new(1.0, 2.0);
1431 c.add_to_imaginary_part(&f64::NAN);
1432 }
1433
1434 #[test]
1435 fn multiply_real_part() {
1436 let mut c = Complex::new(1.0, 2.0);
1437 c.multiply_real_part(&3.0);
1438 assert_eq!(c.re, 3.0);
1439 assert_eq!(c.im, 2.0);
1440
1441 c.multiply_real_part(&-2.0);
1442 assert_eq!(c.re, -6.0);
1443 assert_eq!(c.im, 2.0);
1444 }
1445
1446 #[cfg(debug_assertions)]
1447 #[test]
1448 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1449 fn multiply_real_part_nan() {
1450 let mut c = Complex::new(1.0, 2.0);
1451 c.multiply_real_part(&f64::NAN);
1452 }
1453
1454 #[test]
1455 fn multiply_imaginary_part() {
1456 let mut c = Complex::new(1.0, 2.0);
1457 c.multiply_imaginary_part(&3.0);
1458 assert_eq!(c.re, 1.0);
1459 assert_eq!(c.im, 6.0);
1460
1461 c.multiply_imaginary_part(&-0.5);
1462 assert_eq!(c.re, 1.0);
1463 assert_eq!(c.im, -3.0);
1464 }
1465
1466 #[cfg(debug_assertions)]
1467 #[test]
1468 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1469 fn multiply_imaginary_part_nan() {
1470 let mut c = Complex::new(1.0, 2.0);
1471 c.multiply_imaginary_part(&f64::NAN);
1472 }
1473
1474 #[test]
1475 fn set_real_part() {
1476 let mut c = Complex::new(1.0, 2.0);
1477 c.set_real_part(3.0);
1478 assert_eq!(c.re, 3.0);
1479 assert_eq!(c.im, 2.0);
1480
1481 c.set_real_part(-4.0);
1482 assert_eq!(c.re, -4.0);
1483 assert_eq!(c.im, 2.0);
1484 }
1485
1486 #[cfg(debug_assertions)]
1487 #[test]
1488 #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1489 fn set_real_part_nan() {
1490 let mut c = Complex::new(1.0, 2.0);
1491 c.set_real_part(f64::NAN);
1492 }
1493
1494 #[test]
1495 fn set_imaginary_part() {
1496 let mut c = Complex::new(1.0, 2.0);
1497 c.set_imaginary_part(3.0);
1498 assert_eq!(c.re, 1.0);
1499 assert_eq!(c.im, 3.0);
1500
1501 c.set_imaginary_part(-4.0);
1502 assert_eq!(c.re, 1.0);
1503 assert_eq!(c.im, -4.0);
1504 }
1505
1506 #[cfg(debug_assertions)]
1507 #[test]
1508 #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1509 fn set_imaginary_part_nan() {
1510 let mut c = Complex::new(1.0, 2.0);
1511 c.set_imaginary_part(f64::NAN);
1512 }
1513
1514 #[test]
1515 #[allow(clippy::op_ref)]
1516 fn multiply_ref() {
1517 let c1 = Complex::new(1.0, 2.0);
1518 let c2 = Complex::new(3.0, 4.0);
1519 let result = c1 * &c2;
1520 assert_eq!(result, Complex::new(-5.0, 10.0)); }
1522 }
1523}