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 precision_tracking;
1102
1103pub mod scientific_types;
1105
1106#[cfg(feature = "arbitrary-precision")]
1108pub mod arbitrary_precision;
1109
1110pub mod stability;
1112
1113pub mod stable_algorithms;
1115
1116pub mod advanced_simd {
1121 #[allow(unused_imports)]
1122 use super::*;
1123
1124 #[cfg(target_arch = "aarch64")]
1125 use std::arch::aarch64::*;
1126 #[cfg(target_arch = "x86_64")]
1127 use std::arch::x86_64::*;
1128
1129 #[inline]
1131 pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1132 debug_assert_eq!(a.len(), b.len());
1133 debug_assert_eq!(a.len(), result.len());
1134
1135 let len = a.len();
1136 let mut i = 0;
1137
1138 #[cfg(target_arch = "x86_64")]
1140 {
1141 if is_x86_feature_detected!("avx2") {
1142 unsafe {
1143 while i + 8 <= len {
1144 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1145 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1146 let vr = _mm256_add_ps(va, vb);
1147 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1148 i += 8;
1149 }
1150 }
1151 }
1152 else if is_x86_feature_detected!("sse") {
1154 unsafe {
1155 while i + 4 <= len {
1156 let va = _mm_loadu_ps(a.as_ptr().add(i));
1157 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1158 let vr = _mm_add_ps(va, vb);
1159 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1160 i += 4;
1161 }
1162 }
1163 }
1164 }
1165
1166 #[cfg(target_arch = "aarch64")]
1168 {
1169 if std::arch::is_aarch64_feature_detected!("neon") {
1170 unsafe {
1171 while i + 4 <= len {
1172 let va = vld1q_f32(a.as_ptr().add(i));
1173 let vb = vld1q_f32(b.as_ptr().add(i));
1174 let vr = vaddq_f32(va, vb);
1175 vst1q_f32(result.as_mut_ptr().add(i), vr);
1176 i += 4;
1177 }
1178 }
1179 }
1180 }
1181
1182 while i < len {
1184 result[i] = a[i] + b[i];
1185 i += 1;
1186 }
1187 }
1188
1189 #[inline]
1191 pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1192 debug_assert_eq!(a.len(), b.len());
1193 debug_assert_eq!(a.len(), result.len());
1194
1195 let len = a.len();
1196 let mut i = 0;
1197
1198 #[cfg(target_arch = "x86_64")]
1200 {
1201 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1202 unsafe {
1203 while i + 8 <= len {
1204 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1205 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1206 let vr = _mm256_mul_ps(va, vb);
1207 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1208 i += 8;
1209 }
1210 }
1211 } else if is_x86_feature_detected!("sse") {
1212 unsafe {
1213 while i + 4 <= len {
1214 let va = _mm_loadu_ps(a.as_ptr().add(i));
1215 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1216 let vr = _mm_mul_ps(va, vb);
1217 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1218 i += 4;
1219 }
1220 }
1221 }
1222 }
1223
1224 #[cfg(target_arch = "aarch64")]
1226 {
1227 if std::arch::is_aarch64_feature_detected!("neon") {
1228 unsafe {
1229 while i + 4 <= len {
1230 let va = vld1q_f32(a.as_ptr().add(i));
1231 let vb = vld1q_f32(b.as_ptr().add(i));
1232 let vr = vmulq_f32(va, vb);
1233 vst1q_f32(result.as_mut_ptr().add(i), vr);
1234 i += 4;
1235 }
1236 }
1237 }
1238 }
1239
1240 while i < len {
1242 result[i] = a[i] * b[i];
1243 i += 1;
1244 }
1245 }
1246
1247 #[inline]
1249 pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
1250 debug_assert_eq!(a.len(), b.len());
1251 debug_assert_eq!(a.len(), c.len());
1252 debug_assert_eq!(a.len(), result.len());
1253
1254 let len = a.len();
1255 let mut i = 0;
1256
1257 #[cfg(target_arch = "x86_64")]
1259 {
1260 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1261 unsafe {
1262 while i + 8 <= len {
1263 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1264 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1265 let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1266 let vr = _mm256_fmadd_ps(va, vb, vc);
1267 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1268 i += 8;
1269 }
1270 }
1271 } else if is_x86_feature_detected!("sse") {
1272 unsafe {
1273 while i + 4 <= len {
1274 let va = _mm_loadu_ps(a.as_ptr().add(i));
1275 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1276 let vc = _mm_loadu_ps(c.as_ptr().add(i));
1277 let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1278 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1279 i += 4;
1280 }
1281 }
1282 }
1283 }
1284
1285 #[cfg(target_arch = "aarch64")]
1287 {
1288 if std::arch::is_aarch64_feature_detected!("neon") {
1289 unsafe {
1290 while i + 4 <= len {
1291 let va = vld1q_f32(a.as_ptr().add(i));
1292 let vb = vld1q_f32(b.as_ptr().add(i));
1293 let vc = vld1q_f32(c.as_ptr().add(i));
1294 let vr = vfmaq_f32(vc, va, vb);
1295 vst1q_f32(result.as_mut_ptr().add(i), vr);
1296 i += 4;
1297 }
1298 }
1299 }
1300 }
1301
1302 while i < len {
1304 result[i] = a[i] * b[i] + c[0];
1305 i += 1;
1306 }
1307 }
1308
1309 #[inline]
1311 pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1312 debug_assert_eq!(a.len(), b.len());
1313
1314 let len = a.len();
1315 let mut i = 0;
1316 let mut sum = 0.0f32;
1317
1318 #[cfg(target_arch = "x86_64")]
1320 {
1321 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1322 unsafe {
1323 let mut acc = _mm256_setzero_ps();
1324 while i + 8 <= len {
1325 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1326 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1327 acc = _mm256_fmadd_ps(va, vb, acc);
1328 i += 8;
1329 }
1330 let hi = _mm256_extractf128_ps(acc, 1);
1332 let lo = _mm256_castps256_ps128(acc);
1333 let sum4 = _mm_add_ps(hi, lo);
1334 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1335 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1336 sum = _mm_cvtss_f32(sum1);
1337 }
1338 } else if is_x86_feature_detected!("sse") {
1339 unsafe {
1340 let mut acc = _mm_setzero_ps();
1341 while i + 4 <= len {
1342 let va = _mm_loadu_ps(a.as_ptr().add(i));
1343 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1344 acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1345 i += 4;
1346 }
1347 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1349 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1350 sum = _mm_cvtss_f32(sum1);
1351 }
1352 }
1353 }
1354
1355 #[cfg(target_arch = "aarch64")]
1357 {
1358 if std::arch::is_aarch64_feature_detected!("neon") {
1359 unsafe {
1360 let mut acc = vdupq_n_f32(0.0);
1361 while i + 4 <= len {
1362 let va = vld1q_f32(a.as_ptr().add(i));
1363 let vb = vld1q_f32(b.as_ptr().add(i));
1364 acc = vfmaq_f32(acc, va, vb);
1365 i += 4;
1366 }
1367 sum = vaddvq_f32(acc);
1369 }
1370 }
1371 }
1372
1373 while i < len {
1375 sum += a[i] * b[i];
1376 i += 1;
1377 }
1378
1379 sum
1380 }
1381
1382 #[inline]
1384 pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1385 let len = data.len();
1386 let mut i = 0;
1387 let mut sum = 0.0f32;
1388
1389 #[cfg(target_arch = "x86_64")]
1391 {
1392 if is_x86_feature_detected!("avx2") {
1393 unsafe {
1394 let mut acc = _mm256_setzero_ps();
1395 while i + 8 <= len {
1396 let v = _mm256_loadu_ps(data.as_ptr().add(i));
1397 acc = _mm256_add_ps(acc, v);
1398 i += 8;
1399 }
1400 let hi = _mm256_extractf128_ps(acc, 1);
1402 let lo = _mm256_castps256_ps128(acc);
1403 let sum4 = _mm_add_ps(hi, lo);
1404 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1405 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1406 sum = _mm_cvtss_f32(sum1);
1407 }
1408 } else if is_x86_feature_detected!("sse") {
1409 unsafe {
1410 let mut acc = _mm_setzero_ps();
1411 while i + 4 <= len {
1412 let v = _mm_loadu_ps(data.as_ptr().add(i));
1413 acc = _mm_add_ps(acc, v);
1414 i += 4;
1415 }
1416 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1417 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1418 sum = _mm_cvtss_f32(sum1);
1419 }
1420 }
1421 }
1422
1423 #[cfg(target_arch = "aarch64")]
1425 {
1426 if std::arch::is_aarch64_feature_detected!("neon") {
1427 unsafe {
1428 let mut acc = vdupq_n_f32(0.0);
1429 while i + 4 <= len {
1430 let v = vld1q_f32(data.as_ptr().add(i));
1431 acc = vaddq_f32(acc, v);
1432 i += 4;
1433 }
1434 sum = vaddvq_f32(acc);
1435 }
1436 }
1437 }
1438
1439 while i < len {
1441 sum += data[i];
1442 i += 1;
1443 }
1444
1445 sum
1446 }
1447}
1448
1449#[cfg(test)]
1450mod tests {
1451 use super::*;
1452
1453 #[test]
1454 fn test_scientific_number_f32() {
1455 let a: f32 = 3.0;
1456 let b: f32 = 4.0;
1457
1458 assert_eq!(a.abs(), 3.0);
1459 assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1460 assert_eq!(a.square(), 9.0);
1461 assert_eq!(a.max(b), 4.0);
1462 assert_eq!(a.min(b), 3.0);
1463 assert!(a.is_finite());
1464 assert_eq!(a.to_f64(), Some(3.0));
1465 assert_eq!(<f32 as ScientificNumber>::from_f64(3.5), Some(3.5));
1466 }
1467
1468 #[test]
1469 fn test_scientific_number_f64() {
1470 let a: f64 = 3.0;
1471 let b: f64 = 4.0;
1472
1473 assert_eq!(a.abs(), 3.0);
1474 assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1475 assert_eq!(a.square(), 9.0);
1476 assert_eq!(a.max(b), 4.0);
1477 assert_eq!(a.min(b), 3.0);
1478 assert!(a.is_finite());
1479 assert_eq!(a.to_f64(), Some(3.0));
1480 assert_eq!(<f64 as ScientificNumber>::from_f64(3.5), Some(3.5));
1481 }
1482
1483 #[test]
1484 fn test_real_number_f32() {
1485 let a: f32 = 3.0;
1486
1487 assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1488 assert_eq!(a.exp(), (3.0_f32).exp());
1489 assert_eq!(a.ln(), (3.0_f32).ln());
1490 assert_eq!(a.sin(), (3.0_f32).sin());
1491 assert_eq!(a.cos(), (3.0_f32).cos());
1492 assert_eq!(a.powf(2.0), 9.0);
1493 }
1494
1495 #[test]
1496 fn test_real_number_f64() {
1497 let a: f64 = 3.0;
1498
1499 assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1500 assert_eq!(a.exp(), (3.0_f64).exp());
1501 assert_eq!(a.ln(), (3.0_f64).ln());
1502 assert_eq!(a.sin(), (3.0_f64).sin());
1503 assert_eq!(a.cos(), (3.0_f64).cos());
1504 assert_eq!(a.powf(2.0), 9.0);
1505 }
1506
1507 #[test]
1508 fn test_scientific_integer_i32() {
1509 let a: i32 = 12;
1510 let b: i32 = 8;
1511
1512 assert_eq!(a.gcd(b), 4);
1513 assert_eq!(a.lcm(b), 24);
1514 assert!(!a.is_prime());
1515 assert!(11_i32.is_prime());
1516 assert!(a.is_even());
1517 assert!(!a.is_odd());
1518 assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial().expect("Operation failed"), 120);
1520 assert_eq!(5_i32.binomial(2), 10); }
1522
1523 #[test]
1524 fn test_numeric_conversion() {
1525 let a: f64 = 3.5;
1526 let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1527 assert_eq!(b, 3);
1528
1529 let c: f32 = 100.5;
1530 let d: f64 = c.convert();
1531 assert_eq!(d, 100.5);
1532
1533 let e: i32 = 100;
1534 let f: f32 = e.convert();
1535 assert_eq!(f, 100.0);
1536 }
1537
1538 #[test]
1539 fn test_angle_conversion() {
1540 let degrees: f64 = 180.0;
1541 let radians = <f64 as AngleConversion>::to_radians(°rees).expect("Operation failed");
1542 assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1543
1544 let radians: f64 = std::f64::consts::PI / 2.0;
1545 let degrees = <f64 as AngleConversion>::to_degrees(&radians).expect("Operation failed");
1546 assert!((degrees - 90.0).abs() < 1e-10);
1547 }
1548
1549 #[test]
1550 fn test_scalar() {
1551 let a = Scalar::new(3.0_f64);
1552 let b = Scalar::new(4.0_f64);
1553
1554 assert_eq!((a + b).value(), 7.0);
1555 assert_eq!((a - b).value(), -1.0);
1556 assert_eq!((a * b).value(), 12.0);
1557 assert_eq!((a / b).value(), 0.75);
1558 assert_eq!((-a).value(), -3.0);
1559
1560 let c: Scalar<f64> = 5.0.into();
1561 assert_eq!(c.value(), 5.0);
1562 }
1563}