1use crate::error::{CoreError, CoreResult, ErrorContext};
17use std::fmt::Debug;
18use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
19
20pub use num_traits::{
26 self,
27 bounds::Bounded,
28 cast::{AsPrimitive, FromPrimitive, NumCast, ToPrimitive},
29 float::{Float, FloatConst},
30 identities::{One, Zero},
31 int::PrimInt,
32 ops::{
33 checked::*,
34 inv::Inv,
35 mul_add::{MulAdd, MulAddAssign},
36 saturating::*,
37 wrapping::*,
38 },
39 pow::{checked_pow, Pow},
40 real::Real,
41 sign::{Signed, Unsigned},
42 Num, NumAssign, NumAssignOps, NumAssignRef, NumOps, NumRef,
43};
44
45pub use num_complex::{self, Complex, Complex32, Complex64, ComplexFloat};
47
48pub use num_integer::{
50 self, div_ceil, div_floor, div_mod_floor, gcd, gcd_lcm, lcm, Average, ExtendedGcd, Integer,
51 Roots,
52};
53
54pub trait ScientificNumber:
63 Num
64 + Clone
65 + Copy
66 + PartialOrd
67 + Debug
68 + Zero
69 + One
70 + Add<Output = Self>
71 + Sub<Output = Self>
72 + Mul<Output = Self>
73 + Div<Output = Self>
74 + AddAssign
75 + SubAssign
76 + MulAssign
77 + DivAssign
78 + NumCast
79{
80 #[must_use]
82 fn abs(self) -> Self;
83
84 #[must_use]
86 fn sqrt(self) -> Self;
87
88 #[must_use]
90 fn square(self) -> Self {
91 self * self
92 }
93
94 #[must_use]
96 fn max(self, other: Self) -> Self;
97
98 #[must_use]
100 fn min(self, other: Self) -> Self;
101
102 #[must_use]
104 fn is_finite(self) -> bool;
105
106 #[must_use]
108 fn to_f64(self) -> Option<f64>;
109
110 #[must_use]
112 fn from_f64(value: f64) -> Option<Self>;
113
114 #[must_use]
116 fn from_le_bytes(bytes: &[u8]) -> Self;
117
118 #[must_use]
120 fn from_be_bytes(bytes: &[u8]) -> Self;
121
122 #[must_use]
124 fn to_le_bytes(self) -> Vec<u8>;
125
126 #[must_use]
128 fn to_be_bytes(self) -> Vec<u8>;
129}
130
131pub trait RealNumber: ScientificNumber + Float {
133 #[must_use]
135 fn epsilon() -> Self;
136
137 #[must_use]
139 fn exp(self) -> Self;
140
141 #[must_use]
143 fn ln(self) -> Self;
144
145 #[must_use]
147 fn log10(self) -> Self;
148
149 #[must_use]
151 fn log2(self) -> Self;
152
153 #[must_use]
155 fn sin(self) -> Self;
156
157 #[must_use]
159 fn cos(self) -> Self;
160
161 #[must_use]
163 fn tan(self) -> Self;
164
165 #[must_use]
167 fn sinh(self) -> Self;
168
169 #[must_use]
171 fn cosh(self) -> Self;
172
173 #[must_use]
175 fn tanh(self) -> Self;
176
177 #[must_use]
179 fn asin(self) -> Self;
180
181 #[must_use]
183 fn acos(self) -> Self;
184
185 #[must_use]
187 fn atan(self) -> Self;
188
189 #[must_use]
191 fn atan2(self, other: Self) -> Self;
192
193 #[must_use]
195 fn powf(self, n: Self) -> Self;
196
197 #[must_use]
199 fn powi(self, n: i32) -> Self;
200
201 #[must_use]
203 fn factorial(self) -> Self;
204}
205
206pub trait ComplexNumber: ScientificNumber {
208 type RealPart: RealNumber;
210
211 #[must_use]
213 fn re(&self) -> Self::RealPart;
214
215 #[must_use]
217 fn im(&self) -> Self::RealPart;
218
219 #[must_use]
221 fn from_parts(re: Self::RealPart, im: Self::RealPart) -> Self;
222
223 #[must_use]
225 fn conj(self) -> Self;
226
227 #[must_use]
229 fn abs(self) -> Self::RealPart;
230
231 #[must_use]
233 fn arg(self) -> Self::RealPart;
234
235 #[must_use]
237 fn to_polar(self) -> (Self::RealPart, Self::RealPart);
238
239 #[must_use]
241 fn from_polar(r: Self::RealPart, theta: Self::RealPart) -> Self;
242
243 #[must_use]
245 fn exp(self) -> Self;
246
247 #[must_use]
249 fn ln(self) -> Self;
250
251 #[must_use]
253 fn powc(self, exp: Self) -> Self;
254
255 #[must_use]
257 fn powf(self, exp: Self::RealPart) -> Self;
258
259 #[must_use]
261 fn sqrt(self) -> Self;
262}
263
264pub trait ScientificInteger: ScientificNumber + Eq {
266 #[must_use]
268 fn gcd(self, other: Self) -> Self;
269
270 #[must_use]
272 fn lcm(self, other: Self) -> Self;
273
274 #[must_use]
276 fn is_prime(self) -> bool;
277
278 #[must_use]
280 fn is_even(self) -> bool;
281
282 #[must_use]
284 fn is_odd(self) -> bool;
285
286 #[must_use]
288 fn mod_pow(self, exp: Self, modulus: Self) -> Self;
289
290 fn factorial(self) -> CoreResult<Self>;
292
293 #[must_use]
295 fn binomial(self, k: Self) -> Self;
296}
297
298pub trait SparseElement:
333 Copy + PartialEq + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Default + Debug
334{
335 #[must_use]
339 fn sparse_zero() -> Self;
340
341 #[must_use]
345 fn sparse_one() -> Self;
346
347 #[deprecated(
354 since = "0.1.0",
355 note = "Use `sparse_zero()` instead to avoid ambiguity with num_traits::Zero"
356 )]
357 #[must_use]
358 fn zero() -> Self {
359 Self::sparse_zero()
360 }
361
362 #[deprecated(
369 since = "0.1.0",
370 note = "Use `sparse_one()` instead to avoid ambiguity with num_traits::One"
371 )]
372 #[must_use]
373 fn one() -> Self {
374 Self::sparse_one()
375 }
376
377 #[must_use]
379 fn is_zero(&self) -> bool {
380 *self == Self::sparse_zero()
381 }
382}
383
384impl SparseElement for u8 {
386 fn sparse_zero() -> Self {
387 0
388 }
389 fn sparse_one() -> Self {
390 1
391 }
392}
393
394impl SparseElement for u16 {
395 fn sparse_zero() -> Self {
396 0
397 }
398 fn sparse_one() -> Self {
399 1
400 }
401}
402
403impl SparseElement for u32 {
404 fn sparse_zero() -> Self {
405 0
406 }
407 fn sparse_one() -> Self {
408 1
409 }
410}
411
412impl SparseElement for u64 {
413 fn sparse_zero() -> Self {
414 0
415 }
416 fn sparse_one() -> Self {
417 1
418 }
419}
420
421impl SparseElement for u128 {
422 fn sparse_zero() -> Self {
423 0
424 }
425 fn sparse_one() -> Self {
426 1
427 }
428}
429
430impl SparseElement for usize {
431 fn sparse_zero() -> Self {
432 0
433 }
434 fn sparse_one() -> Self {
435 1
436 }
437}
438
439impl SparseElement for i8 {
441 fn sparse_zero() -> Self {
442 0
443 }
444 fn sparse_one() -> Self {
445 1
446 }
447}
448
449impl SparseElement for i16 {
450 fn sparse_zero() -> Self {
451 0
452 }
453 fn sparse_one() -> Self {
454 1
455 }
456}
457
458impl SparseElement for i32 {
459 fn sparse_zero() -> Self {
460 0
461 }
462 fn sparse_one() -> Self {
463 1
464 }
465}
466
467impl SparseElement for i64 {
468 fn sparse_zero() -> Self {
469 0
470 }
471 fn sparse_one() -> Self {
472 1
473 }
474}
475
476impl SparseElement for i128 {
477 fn sparse_zero() -> Self {
478 0
479 }
480 fn sparse_one() -> Self {
481 1
482 }
483}
484
485impl SparseElement for isize {
486 fn sparse_zero() -> Self {
487 0
488 }
489 fn sparse_one() -> Self {
490 1
491 }
492}
493
494impl SparseElement for f32 {
496 fn sparse_zero() -> Self {
497 0.0
498 }
499 fn sparse_one() -> Self {
500 1.0
501 }
502}
503
504impl SparseElement for f64 {
505 fn sparse_zero() -> Self {
506 0.0
507 }
508 fn sparse_one() -> Self {
509 1.0
510 }
511}
512
513impl ScientificNumber for f32 {
515 fn abs(self) -> Self {
516 self.abs()
517 }
518
519 fn sqrt(self) -> Self {
520 self.sqrt()
521 }
522
523 fn max(self, other: Self) -> Self {
524 self.max(other)
525 }
526
527 fn min(self, other: Self) -> Self {
528 self.min(other)
529 }
530
531 fn is_finite(self) -> bool {
532 self.is_finite()
533 }
534
535 fn to_f64(self) -> Option<f64> {
536 Some(self as f64)
537 }
538
539 fn from_f64(value: f64) -> Option<Self> {
540 if value.is_finite() && value <= Self::MAX as f64 && value >= Self::MIN as f64 {
541 Some(value as f32)
542 } else {
543 None
544 }
545 }
546
547 fn from_le_bytes(bytes: &[u8]) -> Self {
548 let mut array = [0u8; 4];
549 array.copy_from_slice(&bytes[..4]);
550 f32::from_le_bytes(array)
551 }
552
553 fn from_be_bytes(bytes: &[u8]) -> Self {
554 let mut array = [0u8; 4];
555 array.copy_from_slice(&bytes[..4]);
556 f32::from_be_bytes(array)
557 }
558
559 fn to_le_bytes(self) -> Vec<u8> {
560 self.to_le_bytes().to_vec()
561 }
562
563 fn to_be_bytes(self) -> Vec<u8> {
564 self.to_be_bytes().to_vec()
565 }
566}
567
568impl RealNumber for f32 {
570 fn epsilon() -> Self {
571 Self::EPSILON
572 }
573
574 fn exp(self) -> Self {
575 self.exp()
576 }
577
578 fn ln(self) -> Self {
579 self.ln()
580 }
581
582 fn log10(self) -> Self {
583 self.log10()
584 }
585
586 fn log2(self) -> Self {
587 self.log2()
588 }
589
590 fn sin(self) -> Self {
591 self.sin()
592 }
593
594 fn cos(self) -> Self {
595 self.cos()
596 }
597
598 fn tan(self) -> Self {
599 self.tan()
600 }
601
602 fn sinh(self) -> Self {
603 self.sinh()
604 }
605
606 fn cosh(self) -> Self {
607 self.cosh()
608 }
609
610 fn tanh(self) -> Self {
611 self.tanh()
612 }
613
614 fn asin(self) -> Self {
615 self.asin()
616 }
617
618 fn acos(self) -> Self {
619 self.acos()
620 }
621
622 fn atan(self) -> Self {
623 self.atan()
624 }
625
626 fn atan2(self, other: Self) -> Self {
627 self.atan2(other)
628 }
629
630 fn powf(self, n: Self) -> Self {
631 self.powf(n)
632 }
633
634 fn powi(self, n: i32) -> Self {
635 self.powi(n)
636 }
637
638 fn factorial(self) -> Self {
639 if self < 0.0 {
640 return Self::NAN;
641 }
642
643 if self != self.trunc() || self > 100.0 {
645 const SQRT_TWO_PI: f32 = 2.506_628_3;
646 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
647 }
648
649 let mut result = 1.0;
650 let n = self as u32;
651 for i in 2..=n {
652 result *= i as f32;
653 }
654
655 result
656 }
657}
658
659impl ScientificNumber for f64 {
661 fn abs(self) -> Self {
662 self.abs()
663 }
664
665 fn sqrt(self) -> Self {
666 self.sqrt()
667 }
668
669 fn max(self, other: Self) -> Self {
670 self.max(other)
671 }
672
673 fn min(self, other: Self) -> Self {
674 self.min(other)
675 }
676
677 fn is_finite(self) -> bool {
678 self.is_finite()
679 }
680
681 fn to_f64(self) -> Option<f64> {
682 Some(self)
683 }
684
685 fn from_f64(value: f64) -> Option<Self> {
686 Some(value)
687 }
688
689 fn from_le_bytes(bytes: &[u8]) -> Self {
690 let mut array = [0u8; 8];
691 array.copy_from_slice(&bytes[..8]);
692 f64::from_le_bytes(array)
693 }
694
695 fn from_be_bytes(bytes: &[u8]) -> Self {
696 let mut array = [0u8; 8];
697 array.copy_from_slice(&bytes[..8]);
698 f64::from_be_bytes(array)
699 }
700
701 fn to_le_bytes(self) -> Vec<u8> {
702 self.to_le_bytes().to_vec()
703 }
704
705 fn to_be_bytes(self) -> Vec<u8> {
706 self.to_be_bytes().to_vec()
707 }
708}
709
710impl RealNumber for f64 {
712 fn epsilon() -> Self {
713 Self::EPSILON
714 }
715
716 fn exp(self) -> Self {
717 self.exp()
718 }
719
720 fn ln(self) -> Self {
721 self.ln()
722 }
723
724 fn log10(self) -> Self {
725 self.log10()
726 }
727
728 fn log2(self) -> Self {
729 self.log2()
730 }
731
732 fn sin(self) -> Self {
733 self.sin()
734 }
735
736 fn cos(self) -> Self {
737 self.cos()
738 }
739
740 fn tan(self) -> Self {
741 self.tan()
742 }
743
744 fn sinh(self) -> Self {
745 self.sinh()
746 }
747
748 fn cosh(self) -> Self {
749 self.cosh()
750 }
751
752 fn tanh(self) -> Self {
753 self.tanh()
754 }
755
756 fn asin(self) -> Self {
757 self.asin()
758 }
759
760 fn acos(self) -> Self {
761 self.acos()
762 }
763
764 fn atan(self) -> Self {
765 self.atan()
766 }
767
768 fn atan2(self, other: Self) -> Self {
769 self.atan2(other)
770 }
771
772 fn powf(self, n: Self) -> Self {
773 self.powf(n)
774 }
775
776 fn powi(self, n: i32) -> Self {
777 self.powi(n)
778 }
779
780 fn factorial(self) -> Self {
781 if self < 0.0 {
782 return Self::NAN;
783 }
784
785 if self != self.trunc() || self > 170.0 {
787 const SQRT_TWO_PI: f64 = 2.506_628_274_631_000_2;
788 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
789 }
790
791 let mut result = 1.0;
792 let n = self as u32;
793 for i in 2..=n {
794 result *= i as f64;
795 }
796
797 result
798 }
799}
800
801impl ScientificNumber for i32 {
803 fn abs(self) -> Self {
804 self.abs()
805 }
806
807 fn sqrt(self) -> Self {
808 (self as f64).sqrt() as i32
809 }
810
811 fn max(self, other: Self) -> Self {
812 std::cmp::max(self, other)
813 }
814
815 fn min(self, other: Self) -> Self {
816 std::cmp::min(self, other)
817 }
818
819 fn is_finite(self) -> bool {
820 true }
822
823 fn to_f64(self) -> Option<f64> {
824 Some(self as f64)
825 }
826
827 fn from_f64(value: f64) -> Option<Self> {
828 if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
829 Some(value as i32)
830 } else {
831 None
832 }
833 }
834
835 fn from_le_bytes(bytes: &[u8]) -> Self {
836 let mut array = [0u8; 4];
837 array.copy_from_slice(&bytes[..4]);
838 i32::from_le_bytes(array)
839 }
840
841 fn from_be_bytes(bytes: &[u8]) -> Self {
842 let mut array = [0u8; 4];
843 array.copy_from_slice(&bytes[..4]);
844 i32::from_be_bytes(array)
845 }
846
847 fn to_le_bytes(self) -> Vec<u8> {
848 self.to_le_bytes().to_vec()
849 }
850
851 fn to_be_bytes(self) -> Vec<u8> {
852 self.to_be_bytes().to_vec()
853 }
854}
855
856impl ScientificInteger for i32 {
858 fn gcd(self, other: Self) -> Self {
859 let mut a = self.abs();
860 let mut b = other.abs();
861
862 if a == 0 {
863 return b;
864 }
865 if b == 0 {
866 return a;
867 }
868
869 while b != 0 {
870 let temp = b;
871 b = a % b;
872 a = temp;
873 }
874
875 a
876 }
877
878 fn lcm(self, other: Self) -> Self {
879 if self == 0 || other == 0 {
880 return 0;
881 }
882
883 let gcd = self.gcd(other);
884
885 (self / gcd) * other
886 }
887
888 fn is_prime(self) -> bool {
889 if self <= 1 {
890 return false;
891 }
892 if self <= 3 {
893 return true;
894 }
895 if self % 2 == 0 || self % 3 == 0 {
896 return false;
897 }
898
899 let mut i = 5;
900 while i * i <= self {
901 if self % i == 0 || self % (i + 2) == 0 {
902 return false;
903 }
904 i += 6;
905 }
906
907 true
908 }
909
910 fn is_even(self) -> bool {
911 self % 2 == 0
912 }
913
914 fn is_odd(self) -> bool {
915 self % 2 != 0
916 }
917
918 fn mod_pow(self, exp: Self, modulus: Self) -> Self {
919 if modulus == 1 {
920 return 0;
921 }
922
923 let mut base = self % modulus;
924 let mut result = 1;
925 let mut exponent = exp;
926
927 while exponent > 0 {
928 if exponent % 2 == 1 {
929 result = (result * base) % modulus;
930 }
931 exponent >>= 1;
932 base = (base * base) % modulus;
933 }
934
935 result
936 }
937
938 fn factorial(self) -> CoreResult<Self> {
939 if self < 0 {
940 return Err(CoreError::ValueError(ErrorContext::new(
941 "Factorial not defined for negative numbers".to_string(),
942 )));
943 }
944
945 let mut result = 1;
946 for i in 2..=self {
947 result *= i;
948 }
949
950 Ok(result)
951 }
952
953 fn binomial(self, k: Self) -> Self {
954 if k < 0 || k > self {
955 return 0;
956 }
957
958 let k = std::cmp::min(k, self - k);
959 let mut result = 1;
960
961 for i in 0..k {
962 result = result * (self - i) / (i + 1);
963 }
964
965 result
966 }
967}
968
969pub trait NumericConversion<T> {
971 fn try_convert(self) -> Option<T>;
973
974 fn convert_or(self, default: T) -> T;
976
977 fn convert(self) -> T;
979}
980
981impl<F, T> NumericConversion<T> for F
983where
984 F: NumCast,
985 T: NumCast,
986{
987 fn try_convert(self) -> Option<T> {
988 num_traits::cast(self)
989 }
990
991 fn convert_or(self, default: T) -> T {
992 self.try_convert().unwrap_or(default)
993 }
994
995 fn convert(self) -> T {
996 self.try_convert().expect("Numeric conversion failed")
997 }
998}
999
1000pub trait AngleConversion: Sized {
1002 fn to_radians(&self) -> CoreResult<Self>
1004 where
1005 Self: std::marker::Sized;
1006
1007 fn to_degrees(&self) -> CoreResult<Self>
1009 where
1010 Self: std::marker::Sized;
1011}
1012
1013impl<T: RealNumber> AngleConversion for T {
1015 fn to_radians(&self) -> CoreResult<Self> {
1016 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1017 CoreError::ValueError(ErrorContext::new(
1018 "Failed to convert PI constant to target type".to_string(),
1019 ))
1020 })?;
1021 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1022 CoreError::ValueError(ErrorContext::new(
1023 "Failed to convert 180.0 to target type".to_string(),
1024 ))
1025 })?;
1026 Ok(*self * pi / one_eighty)
1027 }
1028
1029 fn to_degrees(&self) -> CoreResult<Self> {
1030 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1031 CoreError::ValueError(ErrorContext::new(
1032 "Failed to convert PI constant to target type".to_string(),
1033 ))
1034 })?;
1035 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1036 CoreError::ValueError(ErrorContext::new(
1037 "Failed to convert 180.0 to target type".to_string(),
1038 ))
1039 })?;
1040 Ok(*self * one_eighty / pi)
1041 }
1042}
1043
1044#[derive(Clone, Copy, PartialEq, Debug)]
1046pub struct Scalar<T: ScientificNumber>(pub T);
1047
1048impl<T: ScientificNumber> Scalar<T> {
1049 pub fn new(value: T) -> Self {
1051 Scalar(value)
1052 }
1053
1054 pub fn value(&self) -> T {
1056 self.0
1057 }
1058}
1059
1060impl<T: ScientificNumber> From<T> for Scalar<T> {
1061 fn from(value: T) -> Self {
1062 Scalar(value)
1063 }
1064}
1065
1066impl<T: ScientificNumber> Add for Scalar<T> {
1067 type Output = Self;
1068
1069 fn add(self, other: Self) -> Self::Output {
1070 Scalar(self.0 + other.0)
1071 }
1072}
1073
1074impl<T: ScientificNumber> Sub for Scalar<T> {
1075 type Output = Self;
1076
1077 fn sub(self, other: Self) -> Self::Output {
1078 Scalar(self.0 - other.0)
1079 }
1080}
1081
1082impl<T: ScientificNumber> Mul for Scalar<T> {
1083 type Output = Self;
1084
1085 fn mul(self, other: Self) -> Self::Output {
1086 Scalar(self.0 * other.0)
1087 }
1088}
1089
1090impl<T: ScientificNumber> Div for Scalar<T> {
1091 type Output = Self;
1092
1093 fn div(self, other: Self) -> Self::Output {
1094 Scalar(self.0 / other.0)
1095 }
1096}
1097
1098impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
1099 type Output = Self;
1100
1101 fn neg(self) -> Self::Output {
1102 Scalar(self.0.neg())
1103 }
1104}
1105
1106pub mod utilities;
1108
1109pub mod precision_tracking;
1111
1112pub mod scientific_types;
1114
1115#[cfg(feature = "arbitrary-precision")]
1117pub mod arbitrary_precision;
1118
1119pub mod stability;
1121
1122pub mod stable_algorithms;
1124
1125pub mod stability_toolkit;
1127
1128pub mod advanced_simd {
1133 #[allow(unused_imports)]
1134 use super::*;
1135
1136 #[cfg(target_arch = "aarch64")]
1137 use std::arch::aarch64::*;
1138 #[cfg(target_arch = "x86_64")]
1139 use std::arch::x86_64::*;
1140
1141 #[inline]
1143 pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1144 debug_assert_eq!(a.len(), b.len());
1145 debug_assert_eq!(a.len(), result.len());
1146
1147 let len = a.len();
1148 let mut i = 0;
1149
1150 #[cfg(target_arch = "x86_64")]
1152 {
1153 if is_x86_feature_detected!("avx2") {
1154 unsafe {
1155 while i + 8 <= len {
1156 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1157 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1158 let vr = _mm256_add_ps(va, vb);
1159 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1160 i += 8;
1161 }
1162 }
1163 }
1164 else if is_x86_feature_detected!("sse") {
1166 unsafe {
1167 while i + 4 <= len {
1168 let va = _mm_loadu_ps(a.as_ptr().add(i));
1169 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1170 let vr = _mm_add_ps(va, vb);
1171 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1172 i += 4;
1173 }
1174 }
1175 }
1176 }
1177
1178 #[cfg(target_arch = "aarch64")]
1180 {
1181 if std::arch::is_aarch64_feature_detected!("neon") {
1182 unsafe {
1183 while i + 4 <= len {
1184 let va = vld1q_f32(a.as_ptr().add(i));
1185 let vb = vld1q_f32(b.as_ptr().add(i));
1186 let vr = vaddq_f32(va, vb);
1187 vst1q_f32(result.as_mut_ptr().add(i), vr);
1188 i += 4;
1189 }
1190 }
1191 }
1192 }
1193
1194 while i < len {
1196 result[i] = a[i] + b[i];
1197 i += 1;
1198 }
1199 }
1200
1201 #[inline]
1203 pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1204 debug_assert_eq!(a.len(), b.len());
1205 debug_assert_eq!(a.len(), result.len());
1206
1207 let len = a.len();
1208 let mut i = 0;
1209
1210 #[cfg(target_arch = "x86_64")]
1212 {
1213 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1214 unsafe {
1215 while i + 8 <= len {
1216 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1217 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1218 let vr = _mm256_mul_ps(va, vb);
1219 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1220 i += 8;
1221 }
1222 }
1223 } else if is_x86_feature_detected!("sse") {
1224 unsafe {
1225 while i + 4 <= len {
1226 let va = _mm_loadu_ps(a.as_ptr().add(i));
1227 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1228 let vr = _mm_mul_ps(va, vb);
1229 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1230 i += 4;
1231 }
1232 }
1233 }
1234 }
1235
1236 #[cfg(target_arch = "aarch64")]
1238 {
1239 if std::arch::is_aarch64_feature_detected!("neon") {
1240 unsafe {
1241 while i + 4 <= len {
1242 let va = vld1q_f32(a.as_ptr().add(i));
1243 let vb = vld1q_f32(b.as_ptr().add(i));
1244 let vr = vmulq_f32(va, vb);
1245 vst1q_f32(result.as_mut_ptr().add(i), vr);
1246 i += 4;
1247 }
1248 }
1249 }
1250 }
1251
1252 while i < len {
1254 result[i] = a[i] * b[i];
1255 i += 1;
1256 }
1257 }
1258
1259 #[inline]
1261 pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
1262 debug_assert_eq!(a.len(), b.len());
1263 debug_assert_eq!(a.len(), c.len());
1264 debug_assert_eq!(a.len(), result.len());
1265
1266 let len = a.len();
1267 let mut i = 0;
1268
1269 #[cfg(target_arch = "x86_64")]
1271 {
1272 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1273 unsafe {
1274 while i + 8 <= len {
1275 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1276 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1277 let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1278 let vr = _mm256_fmadd_ps(va, vb, vc);
1279 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1280 i += 8;
1281 }
1282 }
1283 } else if is_x86_feature_detected!("sse") {
1284 unsafe {
1285 while i + 4 <= len {
1286 let va = _mm_loadu_ps(a.as_ptr().add(i));
1287 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1288 let vc = _mm_loadu_ps(c.as_ptr().add(i));
1289 let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1290 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1291 i += 4;
1292 }
1293 }
1294 }
1295 }
1296
1297 #[cfg(target_arch = "aarch64")]
1299 {
1300 if std::arch::is_aarch64_feature_detected!("neon") {
1301 unsafe {
1302 while i + 4 <= len {
1303 let va = vld1q_f32(a.as_ptr().add(i));
1304 let vb = vld1q_f32(b.as_ptr().add(i));
1305 let vc = vld1q_f32(c.as_ptr().add(i));
1306 let vr = vfmaq_f32(vc, va, vb);
1307 vst1q_f32(result.as_mut_ptr().add(i), vr);
1308 i += 4;
1309 }
1310 }
1311 }
1312 }
1313
1314 while i < len {
1316 result[i] = a[i] * b[i] + c[0];
1317 i += 1;
1318 }
1319 }
1320
1321 #[inline]
1323 pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1324 debug_assert_eq!(a.len(), b.len());
1325
1326 let len = a.len();
1327 let mut i = 0;
1328 let mut sum = 0.0f32;
1329
1330 #[cfg(target_arch = "x86_64")]
1332 {
1333 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1334 unsafe {
1335 let mut acc = _mm256_setzero_ps();
1336 while i + 8 <= len {
1337 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1338 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1339 acc = _mm256_fmadd_ps(va, vb, acc);
1340 i += 8;
1341 }
1342 let hi = _mm256_extractf128_ps(acc, 1);
1344 let lo = _mm256_castps256_ps128(acc);
1345 let sum4 = _mm_add_ps(hi, lo);
1346 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1347 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1348 sum = _mm_cvtss_f32(sum1);
1349 }
1350 } else if is_x86_feature_detected!("sse") {
1351 unsafe {
1352 let mut acc = _mm_setzero_ps();
1353 while i + 4 <= len {
1354 let va = _mm_loadu_ps(a.as_ptr().add(i));
1355 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1356 acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1357 i += 4;
1358 }
1359 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1361 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1362 sum = _mm_cvtss_f32(sum1);
1363 }
1364 }
1365 }
1366
1367 #[cfg(target_arch = "aarch64")]
1369 {
1370 if std::arch::is_aarch64_feature_detected!("neon") {
1371 unsafe {
1372 let mut acc = vdupq_n_f32(0.0);
1373 while i + 4 <= len {
1374 let va = vld1q_f32(a.as_ptr().add(i));
1375 let vb = vld1q_f32(b.as_ptr().add(i));
1376 acc = vfmaq_f32(acc, va, vb);
1377 i += 4;
1378 }
1379 sum = vaddvq_f32(acc);
1381 }
1382 }
1383 }
1384
1385 while i < len {
1387 sum += a[i] * b[i];
1388 i += 1;
1389 }
1390
1391 sum
1392 }
1393
1394 #[inline]
1396 pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1397 let len = data.len();
1398 let mut i = 0;
1399 let mut sum = 0.0f32;
1400
1401 #[cfg(target_arch = "x86_64")]
1403 {
1404 if is_x86_feature_detected!("avx2") {
1405 unsafe {
1406 let mut acc = _mm256_setzero_ps();
1407 while i + 8 <= len {
1408 let v = _mm256_loadu_ps(data.as_ptr().add(i));
1409 acc = _mm256_add_ps(acc, v);
1410 i += 8;
1411 }
1412 let hi = _mm256_extractf128_ps(acc, 1);
1414 let lo = _mm256_castps256_ps128(acc);
1415 let sum4 = _mm_add_ps(hi, lo);
1416 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1417 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1418 sum = _mm_cvtss_f32(sum1);
1419 }
1420 } else if is_x86_feature_detected!("sse") {
1421 unsafe {
1422 let mut acc = _mm_setzero_ps();
1423 while i + 4 <= len {
1424 let v = _mm_loadu_ps(data.as_ptr().add(i));
1425 acc = _mm_add_ps(acc, v);
1426 i += 4;
1427 }
1428 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1429 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1430 sum = _mm_cvtss_f32(sum1);
1431 }
1432 }
1433 }
1434
1435 #[cfg(target_arch = "aarch64")]
1437 {
1438 if std::arch::is_aarch64_feature_detected!("neon") {
1439 unsafe {
1440 let mut acc = vdupq_n_f32(0.0);
1441 while i + 4 <= len {
1442 let v = vld1q_f32(data.as_ptr().add(i));
1443 acc = vaddq_f32(acc, v);
1444 i += 4;
1445 }
1446 sum = vaddvq_f32(acc);
1447 }
1448 }
1449 }
1450
1451 while i < len {
1453 sum += data[i];
1454 i += 1;
1455 }
1456
1457 sum
1458 }
1459}
1460
1461#[cfg(test)]
1462mod tests {
1463 use super::*;
1464
1465 #[test]
1466 fn test_scientific_number_f32() {
1467 let a: f32 = 3.0;
1468 let b: f32 = 4.0;
1469
1470 assert_eq!(a.abs(), 3.0);
1471 assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1472 assert_eq!(a.square(), 9.0);
1473 assert_eq!(a.max(b), 4.0);
1474 assert_eq!(a.min(b), 3.0);
1475 assert!(a.is_finite());
1476 assert_eq!(a.to_f64(), Some(3.0));
1477 assert_eq!(<f32 as ScientificNumber>::from_f64(3.5), Some(3.5));
1478 }
1479
1480 #[test]
1481 fn test_scientific_number_f64() {
1482 let a: f64 = 3.0;
1483 let b: f64 = 4.0;
1484
1485 assert_eq!(a.abs(), 3.0);
1486 assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1487 assert_eq!(a.square(), 9.0);
1488 assert_eq!(a.max(b), 4.0);
1489 assert_eq!(a.min(b), 3.0);
1490 assert!(a.is_finite());
1491 assert_eq!(a.to_f64(), Some(3.0));
1492 assert_eq!(<f64 as ScientificNumber>::from_f64(3.5), Some(3.5));
1493 }
1494
1495 #[test]
1496 fn test_real_number_f32() {
1497 let a: f32 = 3.0;
1498
1499 assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1500 assert_eq!(a.exp(), (3.0_f32).exp());
1501 assert_eq!(a.ln(), (3.0_f32).ln());
1502 assert_eq!(a.sin(), (3.0_f32).sin());
1503 assert_eq!(a.cos(), (3.0_f32).cos());
1504 assert_eq!(a.powf(2.0), 9.0);
1505 }
1506
1507 #[test]
1508 fn test_real_number_f64() {
1509 let a: f64 = 3.0;
1510
1511 assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1512 assert_eq!(a.exp(), (3.0_f64).exp());
1513 assert_eq!(a.ln(), (3.0_f64).ln());
1514 assert_eq!(a.sin(), (3.0_f64).sin());
1515 assert_eq!(a.cos(), (3.0_f64).cos());
1516 assert_eq!(a.powf(2.0), 9.0);
1517 }
1518
1519 #[test]
1520 fn test_scientific_integer_i32() {
1521 let a: i32 = 12;
1522 let b: i32 = 8;
1523
1524 assert_eq!(a.gcd(b), 4);
1525 assert_eq!(a.lcm(b), 24);
1526 assert!(!a.is_prime());
1527 assert!(11_i32.is_prime());
1528 assert!(a.is_even());
1529 assert!(!a.is_odd());
1530 assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial().expect("Operation failed"), 120);
1532 assert_eq!(5_i32.binomial(2), 10); }
1534
1535 #[test]
1536 fn test_numeric_conversion() {
1537 let a: f64 = 3.5;
1538 let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1539 assert_eq!(b, 3);
1540
1541 let c: f32 = 100.5;
1542 let d: f64 = c.convert();
1543 assert_eq!(d, 100.5);
1544
1545 let e: i32 = 100;
1546 let f: f32 = e.convert();
1547 assert_eq!(f, 100.0);
1548 }
1549
1550 #[test]
1551 fn test_angle_conversion() {
1552 let degrees: f64 = 180.0;
1553 let radians = <f64 as AngleConversion>::to_radians(°rees).expect("Operation failed");
1554 assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1555
1556 let radians: f64 = std::f64::consts::PI / 2.0;
1557 let degrees = <f64 as AngleConversion>::to_degrees(&radians).expect("Operation failed");
1558 assert!((degrees - 90.0).abs() < 1e-10);
1559 }
1560
1561 #[test]
1562 fn test_scalar() {
1563 let a = Scalar::new(3.0_f64);
1564 let b = Scalar::new(4.0_f64);
1565
1566 assert_eq!((a + b).value(), 7.0);
1567 assert_eq!((a - b).value(), -1.0);
1568 assert_eq!((a * b).value(), 12.0);
1569 assert_eq!((a / b).value(), 0.75);
1570 assert_eq!((-a).value(), -3.0);
1571
1572 let c: Scalar<f64> = 5.0.into();
1573 assert_eq!(c.value(), 5.0);
1574 }
1575}