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(note = "Use `sparse_zero()` instead to avoid ambiguity with num_traits::Zero")]
354 #[must_use]
355 fn zero() -> Self {
356 Self::sparse_zero()
357 }
358
359 #[deprecated(note = "Use `sparse_one()` instead to avoid ambiguity with num_traits::One")]
366 #[must_use]
367 fn one() -> Self {
368 Self::sparse_one()
369 }
370
371 #[must_use]
373 fn is_zero(&self) -> bool {
374 *self == Self::sparse_zero()
375 }
376}
377
378impl SparseElement for u8 {
380 fn sparse_zero() -> Self {
381 0
382 }
383 fn sparse_one() -> Self {
384 1
385 }
386}
387
388impl SparseElement for u16 {
389 fn sparse_zero() -> Self {
390 0
391 }
392 fn sparse_one() -> Self {
393 1
394 }
395}
396
397impl SparseElement for u32 {
398 fn sparse_zero() -> Self {
399 0
400 }
401 fn sparse_one() -> Self {
402 1
403 }
404}
405
406impl SparseElement for u64 {
407 fn sparse_zero() -> Self {
408 0
409 }
410 fn sparse_one() -> Self {
411 1
412 }
413}
414
415impl SparseElement for u128 {
416 fn sparse_zero() -> Self {
417 0
418 }
419 fn sparse_one() -> Self {
420 1
421 }
422}
423
424impl SparseElement for usize {
425 fn sparse_zero() -> Self {
426 0
427 }
428 fn sparse_one() -> Self {
429 1
430 }
431}
432
433impl SparseElement for i8 {
435 fn sparse_zero() -> Self {
436 0
437 }
438 fn sparse_one() -> Self {
439 1
440 }
441}
442
443impl SparseElement for i16 {
444 fn sparse_zero() -> Self {
445 0
446 }
447 fn sparse_one() -> Self {
448 1
449 }
450}
451
452impl SparseElement for i32 {
453 fn sparse_zero() -> Self {
454 0
455 }
456 fn sparse_one() -> Self {
457 1
458 }
459}
460
461impl SparseElement for i64 {
462 fn sparse_zero() -> Self {
463 0
464 }
465 fn sparse_one() -> Self {
466 1
467 }
468}
469
470impl SparseElement for i128 {
471 fn sparse_zero() -> Self {
472 0
473 }
474 fn sparse_one() -> Self {
475 1
476 }
477}
478
479impl SparseElement for isize {
480 fn sparse_zero() -> Self {
481 0
482 }
483 fn sparse_one() -> Self {
484 1
485 }
486}
487
488impl SparseElement for f32 {
490 fn sparse_zero() -> Self {
491 0.0
492 }
493 fn sparse_one() -> Self {
494 1.0
495 }
496}
497
498impl SparseElement for f64 {
499 fn sparse_zero() -> Self {
500 0.0
501 }
502 fn sparse_one() -> Self {
503 1.0
504 }
505}
506
507impl ScientificNumber for f32 {
509 fn abs(self) -> Self {
510 self.abs()
511 }
512
513 fn sqrt(self) -> Self {
514 self.sqrt()
515 }
516
517 fn max(self, other: Self) -> Self {
518 self.max(other)
519 }
520
521 fn min(self, other: Self) -> Self {
522 self.min(other)
523 }
524
525 fn is_finite(self) -> bool {
526 self.is_finite()
527 }
528
529 fn to_f64(self) -> Option<f64> {
530 Some(self as f64)
531 }
532
533 fn from_f64(value: f64) -> Option<Self> {
534 if value.is_finite() && value <= Self::MAX as f64 && value >= Self::MIN as f64 {
535 Some(value as f32)
536 } else {
537 None
538 }
539 }
540
541 fn from_le_bytes(bytes: &[u8]) -> Self {
542 let mut array = [0u8; 4];
543 array.copy_from_slice(&bytes[..4]);
544 f32::from_le_bytes(array)
545 }
546
547 fn from_be_bytes(bytes: &[u8]) -> Self {
548 let mut array = [0u8; 4];
549 array.copy_from_slice(&bytes[..4]);
550 f32::from_be_bytes(array)
551 }
552
553 fn to_le_bytes(self) -> Vec<u8> {
554 self.to_le_bytes().to_vec()
555 }
556
557 fn to_be_bytes(self) -> Vec<u8> {
558 self.to_be_bytes().to_vec()
559 }
560}
561
562impl RealNumber for f32 {
564 fn epsilon() -> Self {
565 Self::EPSILON
566 }
567
568 fn exp(self) -> Self {
569 self.exp()
570 }
571
572 fn ln(self) -> Self {
573 self.ln()
574 }
575
576 fn log10(self) -> Self {
577 self.log10()
578 }
579
580 fn log2(self) -> Self {
581 self.log2()
582 }
583
584 fn sin(self) -> Self {
585 self.sin()
586 }
587
588 fn cos(self) -> Self {
589 self.cos()
590 }
591
592 fn tan(self) -> Self {
593 self.tan()
594 }
595
596 fn sinh(self) -> Self {
597 self.sinh()
598 }
599
600 fn cosh(self) -> Self {
601 self.cosh()
602 }
603
604 fn tanh(self) -> Self {
605 self.tanh()
606 }
607
608 fn asin(self) -> Self {
609 self.asin()
610 }
611
612 fn acos(self) -> Self {
613 self.acos()
614 }
615
616 fn atan(self) -> Self {
617 self.atan()
618 }
619
620 fn atan2(self, other: Self) -> Self {
621 self.atan2(other)
622 }
623
624 fn powf(self, n: Self) -> Self {
625 self.powf(n)
626 }
627
628 fn powi(self, n: i32) -> Self {
629 self.powi(n)
630 }
631
632 fn factorial(self) -> Self {
633 if self < 0.0 {
634 return Self::NAN;
635 }
636
637 if self != self.trunc() || self > 100.0 {
639 const SQRT_TWO_PI: f32 = 2.506_628_3;
640 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
641 }
642
643 let mut result = 1.0;
644 let n = self as u32;
645 for i in 2..=n {
646 result *= i as f32;
647 }
648
649 result
650 }
651}
652
653impl ScientificNumber for f64 {
655 fn abs(self) -> Self {
656 self.abs()
657 }
658
659 fn sqrt(self) -> Self {
660 self.sqrt()
661 }
662
663 fn max(self, other: Self) -> Self {
664 self.max(other)
665 }
666
667 fn min(self, other: Self) -> Self {
668 self.min(other)
669 }
670
671 fn is_finite(self) -> bool {
672 self.is_finite()
673 }
674
675 fn to_f64(self) -> Option<f64> {
676 Some(self)
677 }
678
679 fn from_f64(value: f64) -> Option<Self> {
680 Some(value)
681 }
682
683 fn from_le_bytes(bytes: &[u8]) -> Self {
684 let mut array = [0u8; 8];
685 array.copy_from_slice(&bytes[..8]);
686 f64::from_le_bytes(array)
687 }
688
689 fn from_be_bytes(bytes: &[u8]) -> Self {
690 let mut array = [0u8; 8];
691 array.copy_from_slice(&bytes[..8]);
692 f64::from_be_bytes(array)
693 }
694
695 fn to_le_bytes(self) -> Vec<u8> {
696 self.to_le_bytes().to_vec()
697 }
698
699 fn to_be_bytes(self) -> Vec<u8> {
700 self.to_be_bytes().to_vec()
701 }
702}
703
704impl RealNumber for f64 {
706 fn epsilon() -> Self {
707 Self::EPSILON
708 }
709
710 fn exp(self) -> Self {
711 self.exp()
712 }
713
714 fn ln(self) -> Self {
715 self.ln()
716 }
717
718 fn log10(self) -> Self {
719 self.log10()
720 }
721
722 fn log2(self) -> Self {
723 self.log2()
724 }
725
726 fn sin(self) -> Self {
727 self.sin()
728 }
729
730 fn cos(self) -> Self {
731 self.cos()
732 }
733
734 fn tan(self) -> Self {
735 self.tan()
736 }
737
738 fn sinh(self) -> Self {
739 self.sinh()
740 }
741
742 fn cosh(self) -> Self {
743 self.cosh()
744 }
745
746 fn tanh(self) -> Self {
747 self.tanh()
748 }
749
750 fn asin(self) -> Self {
751 self.asin()
752 }
753
754 fn acos(self) -> Self {
755 self.acos()
756 }
757
758 fn atan(self) -> Self {
759 self.atan()
760 }
761
762 fn atan2(self, other: Self) -> Self {
763 self.atan2(other)
764 }
765
766 fn powf(self, n: Self) -> Self {
767 self.powf(n)
768 }
769
770 fn powi(self, n: i32) -> Self {
771 self.powi(n)
772 }
773
774 fn factorial(self) -> Self {
775 if self < 0.0 {
776 return Self::NAN;
777 }
778
779 if self != self.trunc() || self > 170.0 {
781 const SQRT_TWO_PI: f64 = 2.506_628_274_631_000_2;
782 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
783 }
784
785 let mut result = 1.0;
786 let n = self as u32;
787 for i in 2..=n {
788 result *= i as f64;
789 }
790
791 result
792 }
793}
794
795impl ScientificNumber for i32 {
797 fn abs(self) -> Self {
798 self.abs()
799 }
800
801 fn sqrt(self) -> Self {
802 (self as f64).sqrt() as i32
803 }
804
805 fn max(self, other: Self) -> Self {
806 std::cmp::max(self, other)
807 }
808
809 fn min(self, other: Self) -> Self {
810 std::cmp::min(self, other)
811 }
812
813 fn is_finite(self) -> bool {
814 true }
816
817 fn to_f64(self) -> Option<f64> {
818 Some(self as f64)
819 }
820
821 fn from_f64(value: f64) -> Option<Self> {
822 if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
823 Some(value as i32)
824 } else {
825 None
826 }
827 }
828
829 fn from_le_bytes(bytes: &[u8]) -> Self {
830 let mut array = [0u8; 4];
831 array.copy_from_slice(&bytes[..4]);
832 i32::from_le_bytes(array)
833 }
834
835 fn from_be_bytes(bytes: &[u8]) -> Self {
836 let mut array = [0u8; 4];
837 array.copy_from_slice(&bytes[..4]);
838 i32::from_be_bytes(array)
839 }
840
841 fn to_le_bytes(self) -> Vec<u8> {
842 self.to_le_bytes().to_vec()
843 }
844
845 fn to_be_bytes(self) -> Vec<u8> {
846 self.to_be_bytes().to_vec()
847 }
848}
849
850impl ScientificInteger for i32 {
852 fn gcd(self, other: Self) -> Self {
853 let mut a = self.abs();
854 let mut b = other.abs();
855
856 if a == 0 {
857 return b;
858 }
859 if b == 0 {
860 return a;
861 }
862
863 while b != 0 {
864 let temp = b;
865 b = a % b;
866 a = temp;
867 }
868
869 a
870 }
871
872 fn lcm(self, other: Self) -> Self {
873 if self == 0 || other == 0 {
874 return 0;
875 }
876
877 let gcd = self.gcd(other);
878
879 (self / gcd) * other
880 }
881
882 fn is_prime(self) -> bool {
883 if self <= 1 {
884 return false;
885 }
886 if self <= 3 {
887 return true;
888 }
889 if self % 2 == 0 || self % 3 == 0 {
890 return false;
891 }
892
893 let mut i = 5;
894 while i * i <= self {
895 if self % i == 0 || self % (i + 2) == 0 {
896 return false;
897 }
898 i += 6;
899 }
900
901 true
902 }
903
904 fn is_even(self) -> bool {
905 self % 2 == 0
906 }
907
908 fn is_odd(self) -> bool {
909 self % 2 != 0
910 }
911
912 fn mod_pow(self, exp: Self, modulus: Self) -> Self {
913 if modulus == 1 {
914 return 0;
915 }
916
917 let mut base = self % modulus;
918 let mut result = 1;
919 let mut exponent = exp;
920
921 while exponent > 0 {
922 if exponent % 2 == 1 {
923 result = (result * base) % modulus;
924 }
925 exponent >>= 1;
926 base = (base * base) % modulus;
927 }
928
929 result
930 }
931
932 fn factorial(self) -> CoreResult<Self> {
933 if self < 0 {
934 return Err(CoreError::ValueError(ErrorContext::new(
935 "Factorial not defined for negative numbers".to_string(),
936 )));
937 }
938
939 let mut result = 1;
940 for i in 2..=self {
941 result *= i;
942 }
943
944 Ok(result)
945 }
946
947 fn binomial(self, k: Self) -> Self {
948 if k < 0 || k > self {
949 return 0;
950 }
951
952 let k = std::cmp::min(k, self - k);
953 let mut result = 1;
954
955 for i in 0..k {
956 result = result * (self - i) / (i + 1);
957 }
958
959 result
960 }
961}
962
963pub trait NumericConversion<T> {
965 fn try_convert(self) -> Option<T>;
967
968 fn convert_or(self, default: T) -> T;
970
971 fn convert(self) -> T;
973}
974
975impl<F, T> NumericConversion<T> for F
977where
978 F: NumCast,
979 T: NumCast,
980{
981 fn try_convert(self) -> Option<T> {
982 num_traits::cast(self)
983 }
984
985 fn convert_or(self, default: T) -> T {
986 self.try_convert().unwrap_or(default)
987 }
988
989 fn convert(self) -> T {
990 self.try_convert().expect("Numeric conversion failed")
991 }
992}
993
994pub trait AngleConversion: Sized {
996 fn to_radians(&self) -> CoreResult<Self>
998 where
999 Self: std::marker::Sized;
1000
1001 fn to_degrees(&self) -> CoreResult<Self>
1003 where
1004 Self: std::marker::Sized;
1005}
1006
1007impl<T: RealNumber> AngleConversion for T {
1009 fn to_radians(&self) -> CoreResult<Self> {
1010 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1011 CoreError::ValueError(ErrorContext::new(
1012 "Failed to convert PI constant to target type".to_string(),
1013 ))
1014 })?;
1015 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1016 CoreError::ValueError(ErrorContext::new(
1017 "Failed to convert 180.0 to target type".to_string(),
1018 ))
1019 })?;
1020 Ok(*self * pi / one_eighty)
1021 }
1022
1023 fn to_degrees(&self) -> CoreResult<Self> {
1024 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1025 CoreError::ValueError(ErrorContext::new(
1026 "Failed to convert PI constant to target type".to_string(),
1027 ))
1028 })?;
1029 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1030 CoreError::ValueError(ErrorContext::new(
1031 "Failed to convert 180.0 to target type".to_string(),
1032 ))
1033 })?;
1034 Ok(*self * one_eighty / pi)
1035 }
1036}
1037
1038#[derive(Clone, Copy, PartialEq, Debug)]
1040pub struct Scalar<T: ScientificNumber>(pub T);
1041
1042impl<T: ScientificNumber> Scalar<T> {
1043 pub fn new(value: T) -> Self {
1045 Scalar(value)
1046 }
1047
1048 pub fn value(&self) -> T {
1050 self.0
1051 }
1052}
1053
1054impl<T: ScientificNumber> From<T> for Scalar<T> {
1055 fn from(value: T) -> Self {
1056 Scalar(value)
1057 }
1058}
1059
1060impl<T: ScientificNumber> Add for Scalar<T> {
1061 type Output = Self;
1062
1063 fn add(self, other: Self) -> Self::Output {
1064 Scalar(self.0 + other.0)
1065 }
1066}
1067
1068impl<T: ScientificNumber> Sub for Scalar<T> {
1069 type Output = Self;
1070
1071 fn sub(self, other: Self) -> Self::Output {
1072 Scalar(self.0 - other.0)
1073 }
1074}
1075
1076impl<T: ScientificNumber> Mul for Scalar<T> {
1077 type Output = Self;
1078
1079 fn mul(self, other: Self) -> Self::Output {
1080 Scalar(self.0 * other.0)
1081 }
1082}
1083
1084impl<T: ScientificNumber> Div for Scalar<T> {
1085 type Output = Self;
1086
1087 fn div(self, other: Self) -> Self::Output {
1088 Scalar(self.0 / other.0)
1089 }
1090}
1091
1092impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
1093 type Output = Self;
1094
1095 fn neg(self) -> Self::Output {
1096 Scalar(self.0.neg())
1097 }
1098}
1099
1100pub mod utilities;
1102
1103pub mod precision_tracking;
1105
1106pub mod scientific_types;
1108
1109#[cfg(feature = "arbitrary-precision")]
1111pub mod arbitrary_precision;
1112
1113pub mod stability;
1115
1116pub mod stable_algorithms;
1118
1119pub mod stability_toolkit;
1121
1122pub mod advanced_simd {
1127 #[allow(unused_imports)]
1128 use super::*;
1129
1130 #[cfg(target_arch = "aarch64")]
1131 use std::arch::aarch64::*;
1132 #[cfg(target_arch = "x86_64")]
1133 use std::arch::x86_64::*;
1134
1135 #[inline]
1137 pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1138 debug_assert_eq!(a.len(), b.len());
1139 debug_assert_eq!(a.len(), result.len());
1140
1141 let len = a.len();
1142 let mut i = 0;
1143
1144 #[cfg(target_arch = "x86_64")]
1146 {
1147 if is_x86_feature_detected!("avx2") {
1148 unsafe {
1149 while i + 8 <= len {
1150 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1151 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1152 let vr = _mm256_add_ps(va, vb);
1153 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1154 i += 8;
1155 }
1156 }
1157 }
1158 else if is_x86_feature_detected!("sse") {
1160 unsafe {
1161 while i + 4 <= len {
1162 let va = _mm_loadu_ps(a.as_ptr().add(i));
1163 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1164 let vr = _mm_add_ps(va, vb);
1165 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1166 i += 4;
1167 }
1168 }
1169 }
1170 }
1171
1172 #[cfg(target_arch = "aarch64")]
1174 {
1175 if std::arch::is_aarch64_feature_detected!("neon") {
1176 unsafe {
1177 while i + 4 <= len {
1178 let va = vld1q_f32(a.as_ptr().add(i));
1179 let vb = vld1q_f32(b.as_ptr().add(i));
1180 let vr = vaddq_f32(va, vb);
1181 vst1q_f32(result.as_mut_ptr().add(i), vr);
1182 i += 4;
1183 }
1184 }
1185 }
1186 }
1187
1188 while i < len {
1190 result[i] = a[i] + b[i];
1191 i += 1;
1192 }
1193 }
1194
1195 #[inline]
1197 pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1198 debug_assert_eq!(a.len(), b.len());
1199 debug_assert_eq!(a.len(), result.len());
1200
1201 let len = a.len();
1202 let mut i = 0;
1203
1204 #[cfg(target_arch = "x86_64")]
1206 {
1207 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1208 unsafe {
1209 while i + 8 <= len {
1210 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1211 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1212 let vr = _mm256_mul_ps(va, vb);
1213 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1214 i += 8;
1215 }
1216 }
1217 } else if is_x86_feature_detected!("sse") {
1218 unsafe {
1219 while i + 4 <= len {
1220 let va = _mm_loadu_ps(a.as_ptr().add(i));
1221 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1222 let vr = _mm_mul_ps(va, vb);
1223 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1224 i += 4;
1225 }
1226 }
1227 }
1228 }
1229
1230 #[cfg(target_arch = "aarch64")]
1232 {
1233 if std::arch::is_aarch64_feature_detected!("neon") {
1234 unsafe {
1235 while i + 4 <= len {
1236 let va = vld1q_f32(a.as_ptr().add(i));
1237 let vb = vld1q_f32(b.as_ptr().add(i));
1238 let vr = vmulq_f32(va, vb);
1239 vst1q_f32(result.as_mut_ptr().add(i), vr);
1240 i += 4;
1241 }
1242 }
1243 }
1244 }
1245
1246 while i < len {
1248 result[i] = a[i] * b[i];
1249 i += 1;
1250 }
1251 }
1252
1253 #[inline]
1255 pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
1256 debug_assert_eq!(a.len(), b.len());
1257 debug_assert_eq!(a.len(), c.len());
1258 debug_assert_eq!(a.len(), result.len());
1259
1260 let len = a.len();
1261 let mut i = 0;
1262
1263 #[cfg(target_arch = "x86_64")]
1265 {
1266 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1267 unsafe {
1268 while i + 8 <= len {
1269 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1270 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1271 let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1272 let vr = _mm256_fmadd_ps(va, vb, vc);
1273 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1274 i += 8;
1275 }
1276 }
1277 } else if is_x86_feature_detected!("sse") {
1278 unsafe {
1279 while i + 4 <= len {
1280 let va = _mm_loadu_ps(a.as_ptr().add(i));
1281 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1282 let vc = _mm_loadu_ps(c.as_ptr().add(i));
1283 let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1284 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1285 i += 4;
1286 }
1287 }
1288 }
1289 }
1290
1291 #[cfg(target_arch = "aarch64")]
1293 {
1294 if std::arch::is_aarch64_feature_detected!("neon") {
1295 unsafe {
1296 while i + 4 <= len {
1297 let va = vld1q_f32(a.as_ptr().add(i));
1298 let vb = vld1q_f32(b.as_ptr().add(i));
1299 let vc = vld1q_f32(c.as_ptr().add(i));
1300 let vr = vfmaq_f32(vc, va, vb);
1301 vst1q_f32(result.as_mut_ptr().add(i), vr);
1302 i += 4;
1303 }
1304 }
1305 }
1306 }
1307
1308 while i < len {
1310 result[i] = a[i] * b[i] + c[0];
1311 i += 1;
1312 }
1313 }
1314
1315 #[inline]
1317 pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1318 debug_assert_eq!(a.len(), b.len());
1319
1320 let len = a.len();
1321 let mut i = 0;
1322 let mut sum = 0.0f32;
1323
1324 #[cfg(target_arch = "x86_64")]
1326 {
1327 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1328 unsafe {
1329 let mut acc = _mm256_setzero_ps();
1330 while i + 8 <= len {
1331 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1332 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1333 acc = _mm256_fmadd_ps(va, vb, acc);
1334 i += 8;
1335 }
1336 let hi = _mm256_extractf128_ps(acc, 1);
1338 let lo = _mm256_castps256_ps128(acc);
1339 let sum4 = _mm_add_ps(hi, lo);
1340 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1341 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1342 sum = _mm_cvtss_f32(sum1);
1343 }
1344 } else if is_x86_feature_detected!("sse") {
1345 unsafe {
1346 let mut acc = _mm_setzero_ps();
1347 while i + 4 <= len {
1348 let va = _mm_loadu_ps(a.as_ptr().add(i));
1349 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1350 acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1351 i += 4;
1352 }
1353 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1355 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1356 sum = _mm_cvtss_f32(sum1);
1357 }
1358 }
1359 }
1360
1361 #[cfg(target_arch = "aarch64")]
1363 {
1364 if std::arch::is_aarch64_feature_detected!("neon") {
1365 unsafe {
1366 let mut acc = vdupq_n_f32(0.0);
1367 while i + 4 <= len {
1368 let va = vld1q_f32(a.as_ptr().add(i));
1369 let vb = vld1q_f32(b.as_ptr().add(i));
1370 acc = vfmaq_f32(acc, va, vb);
1371 i += 4;
1372 }
1373 sum = vaddvq_f32(acc);
1375 }
1376 }
1377 }
1378
1379 while i < len {
1381 sum += a[i] * b[i];
1382 i += 1;
1383 }
1384
1385 sum
1386 }
1387
1388 #[inline]
1390 pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1391 let len = data.len();
1392 let mut i = 0;
1393 let mut sum = 0.0f32;
1394
1395 #[cfg(target_arch = "x86_64")]
1397 {
1398 if is_x86_feature_detected!("avx2") {
1399 unsafe {
1400 let mut acc = _mm256_setzero_ps();
1401 while i + 8 <= len {
1402 let v = _mm256_loadu_ps(data.as_ptr().add(i));
1403 acc = _mm256_add_ps(acc, v);
1404 i += 8;
1405 }
1406 let hi = _mm256_extractf128_ps(acc, 1);
1408 let lo = _mm256_castps256_ps128(acc);
1409 let sum4 = _mm_add_ps(hi, lo);
1410 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1411 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1412 sum = _mm_cvtss_f32(sum1);
1413 }
1414 } else if is_x86_feature_detected!("sse") {
1415 unsafe {
1416 let mut acc = _mm_setzero_ps();
1417 while i + 4 <= len {
1418 let v = _mm_loadu_ps(data.as_ptr().add(i));
1419 acc = _mm_add_ps(acc, v);
1420 i += 4;
1421 }
1422 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1423 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1424 sum = _mm_cvtss_f32(sum1);
1425 }
1426 }
1427 }
1428
1429 #[cfg(target_arch = "aarch64")]
1431 {
1432 if std::arch::is_aarch64_feature_detected!("neon") {
1433 unsafe {
1434 let mut acc = vdupq_n_f32(0.0);
1435 while i + 4 <= len {
1436 let v = vld1q_f32(data.as_ptr().add(i));
1437 acc = vaddq_f32(acc, v);
1438 i += 4;
1439 }
1440 sum = vaddvq_f32(acc);
1441 }
1442 }
1443 }
1444
1445 while i < len {
1447 sum += data[i];
1448 i += 1;
1449 }
1450
1451 sum
1452 }
1453}
1454
1455#[cfg(test)]
1456mod tests {
1457 use super::*;
1458
1459 #[test]
1460 fn test_scientific_number_f32() {
1461 let a: f32 = 3.0;
1462 let b: f32 = 4.0;
1463
1464 assert_eq!(a.abs(), 3.0);
1465 assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1466 assert_eq!(a.square(), 9.0);
1467 assert_eq!(a.max(b), 4.0);
1468 assert_eq!(a.min(b), 3.0);
1469 assert!(a.is_finite());
1470 assert_eq!(a.to_f64(), Some(3.0));
1471 assert_eq!(<f32 as ScientificNumber>::from_f64(3.5), Some(3.5));
1472 }
1473
1474 #[test]
1475 fn test_scientific_number_f64() {
1476 let a: f64 = 3.0;
1477 let b: f64 = 4.0;
1478
1479 assert_eq!(a.abs(), 3.0);
1480 assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1481 assert_eq!(a.square(), 9.0);
1482 assert_eq!(a.max(b), 4.0);
1483 assert_eq!(a.min(b), 3.0);
1484 assert!(a.is_finite());
1485 assert_eq!(a.to_f64(), Some(3.0));
1486 assert_eq!(<f64 as ScientificNumber>::from_f64(3.5), Some(3.5));
1487 }
1488
1489 #[test]
1490 fn test_real_number_f32() {
1491 let a: f32 = 3.0;
1492
1493 assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1494 assert_eq!(a.exp(), (3.0_f32).exp());
1495 assert_eq!(a.ln(), (3.0_f32).ln());
1496 assert_eq!(a.sin(), (3.0_f32).sin());
1497 assert_eq!(a.cos(), (3.0_f32).cos());
1498 assert_eq!(a.powf(2.0), 9.0);
1499 }
1500
1501 #[test]
1502 fn test_real_number_f64() {
1503 let a: f64 = 3.0;
1504
1505 assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1506 assert_eq!(a.exp(), (3.0_f64).exp());
1507 assert_eq!(a.ln(), (3.0_f64).ln());
1508 assert_eq!(a.sin(), (3.0_f64).sin());
1509 assert_eq!(a.cos(), (3.0_f64).cos());
1510 assert_eq!(a.powf(2.0), 9.0);
1511 }
1512
1513 #[test]
1514 fn test_scientific_integer_i32() {
1515 let a: i32 = 12;
1516 let b: i32 = 8;
1517
1518 assert_eq!(a.gcd(b), 4);
1519 assert_eq!(a.lcm(b), 24);
1520 assert!(!a.is_prime());
1521 assert!(11_i32.is_prime());
1522 assert!(a.is_even());
1523 assert!(!a.is_odd());
1524 assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial().expect("Operation failed"), 120);
1526 assert_eq!(5_i32.binomial(2), 10); }
1528
1529 #[test]
1530 fn test_numeric_conversion() {
1531 let a: f64 = 3.5;
1532 let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1533 assert_eq!(b, 3);
1534
1535 let c: f32 = 100.5;
1536 let d: f64 = c.convert();
1537 assert_eq!(d, 100.5);
1538
1539 let e: i32 = 100;
1540 let f: f32 = e.convert();
1541 assert_eq!(f, 100.0);
1542 }
1543
1544 #[test]
1545 fn test_angle_conversion() {
1546 let degrees: f64 = 180.0;
1547 let radians = <f64 as AngleConversion>::to_radians(°rees).expect("Operation failed");
1548 assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1549
1550 let radians: f64 = std::f64::consts::PI / 2.0;
1551 let degrees = <f64 as AngleConversion>::to_degrees(&radians).expect("Operation failed");
1552 assert!((degrees - 90.0).abs() < 1e-10);
1553 }
1554
1555 #[test]
1556 fn test_scalar() {
1557 let a = Scalar::new(3.0_f64);
1558 let b = Scalar::new(4.0_f64);
1559
1560 assert_eq!((a + b).value(), 7.0);
1561 assert_eq!((a - b).value(), -1.0);
1562 assert_eq!((a * b).value(), 12.0);
1563 assert_eq!((a / b).value(), 0.75);
1564 assert_eq!((-a).value(), -3.0);
1565
1566 let c: Scalar<f64> = 5.0.into();
1567 assert_eq!(c.value(), 5.0);
1568 }
1569}