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-rc.2",
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-rc.2",
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 precision_tracking;
1108
1109pub mod scientific_types;
1111
1112#[cfg(feature = "arbitrary-precision")]
1114pub mod arbitrary_precision;
1115
1116pub mod stability;
1118
1119pub mod stable_algorithms;
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().unwrap(), 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).unwrap();
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).unwrap();
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}