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
298impl ScientificNumber for f32 {
300 fn abs(self) -> Self {
301 self.abs()
302 }
303
304 fn sqrt(self) -> Self {
305 self.sqrt()
306 }
307
308 fn max(self, other: Self) -> Self {
309 self.max(other)
310 }
311
312 fn min(self, other: Self) -> Self {
313 self.min(other)
314 }
315
316 fn is_finite(self) -> bool {
317 self.is_finite()
318 }
319
320 fn to_f64(self) -> Option<f64> {
321 Some(self as f64)
322 }
323
324 fn from_f64(value: f64) -> Option<Self> {
325 if value.is_finite() && value <= Self::MAX as f64 && value >= Self::MIN as f64 {
326 Some(value as f32)
327 } else {
328 None
329 }
330 }
331
332 fn from_le_bytes(bytes: &[u8]) -> Self {
333 let mut array = [0u8; 4];
334 array.copy_from_slice(&bytes[..4]);
335 f32::from_le_bytes(array)
336 }
337
338 fn from_be_bytes(bytes: &[u8]) -> Self {
339 let mut array = [0u8; 4];
340 array.copy_from_slice(&bytes[..4]);
341 f32::from_be_bytes(array)
342 }
343
344 fn to_le_bytes(self) -> Vec<u8> {
345 self.to_le_bytes().to_vec()
346 }
347
348 fn to_be_bytes(self) -> Vec<u8> {
349 self.to_be_bytes().to_vec()
350 }
351}
352
353impl RealNumber for f32 {
355 fn epsilon() -> Self {
356 Self::EPSILON
357 }
358
359 fn exp(self) -> Self {
360 self.exp()
361 }
362
363 fn ln(self) -> Self {
364 self.ln()
365 }
366
367 fn log10(self) -> Self {
368 self.log10()
369 }
370
371 fn log2(self) -> Self {
372 self.log2()
373 }
374
375 fn sin(self) -> Self {
376 self.sin()
377 }
378
379 fn cos(self) -> Self {
380 self.cos()
381 }
382
383 fn tan(self) -> Self {
384 self.tan()
385 }
386
387 fn sinh(self) -> Self {
388 self.sinh()
389 }
390
391 fn cosh(self) -> Self {
392 self.cosh()
393 }
394
395 fn tanh(self) -> Self {
396 self.tanh()
397 }
398
399 fn asin(self) -> Self {
400 self.asin()
401 }
402
403 fn acos(self) -> Self {
404 self.acos()
405 }
406
407 fn atan(self) -> Self {
408 self.atan()
409 }
410
411 fn atan2(self, other: Self) -> Self {
412 self.atan2(other)
413 }
414
415 fn powf(self, n: Self) -> Self {
416 self.powf(n)
417 }
418
419 fn powi(self, n: i32) -> Self {
420 self.powi(n)
421 }
422
423 fn factorial(self) -> Self {
424 if self < 0.0 {
425 return Self::NAN;
426 }
427
428 if self != self.trunc() || self > 100.0 {
430 const SQRT_TWO_PI: f32 = 2.506_628_3;
431 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
432 }
433
434 let mut result = 1.0;
435 let n = self as u32;
436 for i in 2..=n {
437 result *= i as f32;
438 }
439
440 result
441 }
442}
443
444impl ScientificNumber for f64 {
446 fn abs(self) -> Self {
447 self.abs()
448 }
449
450 fn sqrt(self) -> Self {
451 self.sqrt()
452 }
453
454 fn max(self, other: Self) -> Self {
455 self.max(other)
456 }
457
458 fn min(self, other: Self) -> Self {
459 self.min(other)
460 }
461
462 fn is_finite(self) -> bool {
463 self.is_finite()
464 }
465
466 fn to_f64(self) -> Option<f64> {
467 Some(self)
468 }
469
470 fn from_f64(value: f64) -> Option<Self> {
471 Some(value)
472 }
473
474 fn from_le_bytes(bytes: &[u8]) -> Self {
475 let mut array = [0u8; 8];
476 array.copy_from_slice(&bytes[..8]);
477 f64::from_le_bytes(array)
478 }
479
480 fn from_be_bytes(bytes: &[u8]) -> Self {
481 let mut array = [0u8; 8];
482 array.copy_from_slice(&bytes[..8]);
483 f64::from_be_bytes(array)
484 }
485
486 fn to_le_bytes(self) -> Vec<u8> {
487 self.to_le_bytes().to_vec()
488 }
489
490 fn to_be_bytes(self) -> Vec<u8> {
491 self.to_be_bytes().to_vec()
492 }
493}
494
495impl RealNumber for f64 {
497 fn epsilon() -> Self {
498 Self::EPSILON
499 }
500
501 fn exp(self) -> Self {
502 self.exp()
503 }
504
505 fn ln(self) -> Self {
506 self.ln()
507 }
508
509 fn log10(self) -> Self {
510 self.log10()
511 }
512
513 fn log2(self) -> Self {
514 self.log2()
515 }
516
517 fn sin(self) -> Self {
518 self.sin()
519 }
520
521 fn cos(self) -> Self {
522 self.cos()
523 }
524
525 fn tan(self) -> Self {
526 self.tan()
527 }
528
529 fn sinh(self) -> Self {
530 self.sinh()
531 }
532
533 fn cosh(self) -> Self {
534 self.cosh()
535 }
536
537 fn tanh(self) -> Self {
538 self.tanh()
539 }
540
541 fn asin(self) -> Self {
542 self.asin()
543 }
544
545 fn acos(self) -> Self {
546 self.acos()
547 }
548
549 fn atan(self) -> Self {
550 self.atan()
551 }
552
553 fn atan2(self, other: Self) -> Self {
554 self.atan2(other)
555 }
556
557 fn powf(self, n: Self) -> Self {
558 self.powf(n)
559 }
560
561 fn powi(self, n: i32) -> Self {
562 self.powi(n)
563 }
564
565 fn factorial(self) -> Self {
566 if self < 0.0 {
567 return Self::NAN;
568 }
569
570 if self != self.trunc() || self > 170.0 {
572 const SQRT_TWO_PI: f64 = 2.506_628_274_631_000_2;
573 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
574 }
575
576 let mut result = 1.0;
577 let n = self as u32;
578 for i in 2..=n {
579 result *= i as f64;
580 }
581
582 result
583 }
584}
585
586impl ScientificNumber for i32 {
588 fn abs(self) -> Self {
589 self.abs()
590 }
591
592 fn sqrt(self) -> Self {
593 (self as f64).sqrt() as i32
594 }
595
596 fn max(self, other: Self) -> Self {
597 std::cmp::max(self, other)
598 }
599
600 fn min(self, other: Self) -> Self {
601 std::cmp::min(self, other)
602 }
603
604 fn is_finite(self) -> bool {
605 true }
607
608 fn to_f64(self) -> Option<f64> {
609 Some(self as f64)
610 }
611
612 fn from_f64(value: f64) -> Option<Self> {
613 if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
614 Some(value as i32)
615 } else {
616 None
617 }
618 }
619
620 fn from_le_bytes(bytes: &[u8]) -> Self {
621 let mut array = [0u8; 4];
622 array.copy_from_slice(&bytes[..4]);
623 i32::from_le_bytes(array)
624 }
625
626 fn from_be_bytes(bytes: &[u8]) -> Self {
627 let mut array = [0u8; 4];
628 array.copy_from_slice(&bytes[..4]);
629 i32::from_be_bytes(array)
630 }
631
632 fn to_le_bytes(self) -> Vec<u8> {
633 self.to_le_bytes().to_vec()
634 }
635
636 fn to_be_bytes(self) -> Vec<u8> {
637 self.to_be_bytes().to_vec()
638 }
639}
640
641impl ScientificInteger for i32 {
643 fn gcd(self, other: Self) -> Self {
644 let mut a = self.abs();
645 let mut b = other.abs();
646
647 if a == 0 {
648 return b;
649 }
650 if b == 0 {
651 return a;
652 }
653
654 while b != 0 {
655 let temp = b;
656 b = a % b;
657 a = temp;
658 }
659
660 a
661 }
662
663 fn lcm(self, other: Self) -> Self {
664 if self == 0 || other == 0 {
665 return 0;
666 }
667
668 let gcd = self.gcd(other);
669
670 (self / gcd) * other
671 }
672
673 fn is_prime(self) -> bool {
674 if self <= 1 {
675 return false;
676 }
677 if self <= 3 {
678 return true;
679 }
680 if self % 2 == 0 || self % 3 == 0 {
681 return false;
682 }
683
684 let mut i = 5;
685 while i * i <= self {
686 if self % i == 0 || self % (i + 2) == 0 {
687 return false;
688 }
689 i += 6;
690 }
691
692 true
693 }
694
695 fn is_even(self) -> bool {
696 self % 2 == 0
697 }
698
699 fn is_odd(self) -> bool {
700 self % 2 != 0
701 }
702
703 fn mod_pow(self, exp: Self, modulus: Self) -> Self {
704 if modulus == 1 {
705 return 0;
706 }
707
708 let mut base = self % modulus;
709 let mut result = 1;
710 let mut exponent = exp;
711
712 while exponent > 0 {
713 if exponent % 2 == 1 {
714 result = (result * base) % modulus;
715 }
716 exponent >>= 1;
717 base = (base * base) % modulus;
718 }
719
720 result
721 }
722
723 fn factorial(self) -> CoreResult<Self> {
724 if self < 0 {
725 return Err(CoreError::ValueError(ErrorContext::new(
726 "Factorial not defined for negative numbers".to_string(),
727 )));
728 }
729
730 let mut result = 1;
731 for i in 2..=self {
732 result *= i;
733 }
734
735 Ok(result)
736 }
737
738 fn binomial(self, k: Self) -> Self {
739 if k < 0 || k > self {
740 return 0;
741 }
742
743 let k = std::cmp::min(k, self - k);
744 let mut result = 1;
745
746 for i in 0..k {
747 result = result * (self - i) / (i + 1);
748 }
749
750 result
751 }
752}
753
754pub trait NumericConversion<T> {
756 fn try_convert(self) -> Option<T>;
758
759 fn convert_or(self, default: T) -> T;
761
762 fn convert(self) -> T;
764}
765
766impl<F, T> NumericConversion<T> for F
768where
769 F: NumCast,
770 T: NumCast,
771{
772 fn try_convert(self) -> Option<T> {
773 num_traits::cast(self)
774 }
775
776 fn convert_or(self, default: T) -> T {
777 self.try_convert().unwrap_or(default)
778 }
779
780 fn convert(self) -> T {
781 self.try_convert().expect("Numeric conversion failed")
782 }
783}
784
785pub trait AngleConversion: Sized {
787 fn to_radians(&self) -> CoreResult<Self>
789 where
790 Self: std::marker::Sized;
791
792 fn to_degrees(&self) -> CoreResult<Self>
794 where
795 Self: std::marker::Sized;
796}
797
798impl<T: RealNumber> AngleConversion for T {
800 fn to_radians(&self) -> CoreResult<Self> {
801 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
802 CoreError::ValueError(ErrorContext::new(
803 "Failed to convert PI constant to target type".to_string(),
804 ))
805 })?;
806 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
807 CoreError::ValueError(ErrorContext::new(
808 "Failed to convert 180.0 to target type".to_string(),
809 ))
810 })?;
811 Ok(*self * pi / one_eighty)
812 }
813
814 fn to_degrees(&self) -> CoreResult<Self> {
815 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
816 CoreError::ValueError(ErrorContext::new(
817 "Failed to convert PI constant to target type".to_string(),
818 ))
819 })?;
820 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
821 CoreError::ValueError(ErrorContext::new(
822 "Failed to convert 180.0 to target type".to_string(),
823 ))
824 })?;
825 Ok(*self * one_eighty / pi)
826 }
827}
828
829#[derive(Clone, Copy, PartialEq, Debug)]
831pub struct Scalar<T: ScientificNumber>(pub T);
832
833impl<T: ScientificNumber> Scalar<T> {
834 pub fn new(value: T) -> Self {
836 Scalar(value)
837 }
838
839 pub fn value(&self) -> T {
841 self.0
842 }
843}
844
845impl<T: ScientificNumber> From<T> for Scalar<T> {
846 fn from(value: T) -> Self {
847 Scalar(value)
848 }
849}
850
851impl<T: ScientificNumber> Add for Scalar<T> {
852 type Output = Self;
853
854 fn add(self, other: Self) -> Self::Output {
855 Scalar(self.0 + other.0)
856 }
857}
858
859impl<T: ScientificNumber> Sub for Scalar<T> {
860 type Output = Self;
861
862 fn sub(self, other: Self) -> Self::Output {
863 Scalar(self.0 - other.0)
864 }
865}
866
867impl<T: ScientificNumber> Mul for Scalar<T> {
868 type Output = Self;
869
870 fn mul(self, other: Self) -> Self::Output {
871 Scalar(self.0 * other.0)
872 }
873}
874
875impl<T: ScientificNumber> Div for Scalar<T> {
876 type Output = Self;
877
878 fn div(self, other: Self) -> Self::Output {
879 Scalar(self.0 / other.0)
880 }
881}
882
883impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
884 type Output = Self;
885
886 fn neg(self) -> Self::Output {
887 Scalar(self.0.neg())
888 }
889}
890
891pub mod precision_tracking;
893
894pub mod scientific_types;
896
897#[cfg(feature = "arbitrary-precision")]
899pub mod arbitrary_precision;
900
901pub mod stability;
903
904pub mod stable_algorithms;
906
907pub mod advanced_simd {
912 #[allow(unused_imports)]
913 use super::*;
914
915 #[cfg(target_arch = "aarch64")]
916 use std::arch::aarch64::*;
917 #[cfg(target_arch = "x86_64")]
918 use std::arch::x86_64::*;
919
920 #[inline]
922 pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
923 debug_assert_eq!(a.len(), b.len());
924 debug_assert_eq!(a.len(), result.len());
925
926 let len = a.len();
927 let mut i = 0;
928
929 #[cfg(target_arch = "x86_64")]
931 {
932 if is_x86_feature_detected!("avx2") {
933 unsafe {
934 while i + 8 <= len {
935 let va = _mm256_loadu_ps(a.as_ptr().add(i));
936 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
937 let vr = _mm256_add_ps(va, vb);
938 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
939 i += 8;
940 }
941 }
942 }
943 else if is_x86_feature_detected!("sse") {
945 unsafe {
946 while i + 4 <= len {
947 let va = _mm_loadu_ps(a.as_ptr().add(i));
948 let vb = _mm_loadu_ps(b.as_ptr().add(i));
949 let vr = _mm_add_ps(va, vb);
950 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
951 i += 4;
952 }
953 }
954 }
955 }
956
957 #[cfg(target_arch = "aarch64")]
959 {
960 if std::arch::is_aarch64_feature_detected!("neon") {
961 unsafe {
962 while i + 4 <= len {
963 let va = vld1q_f32(a.as_ptr().add(i));
964 let vb = vld1q_f32(b.as_ptr().add(i));
965 let vr = vaddq_f32(va, vb);
966 vst1q_f32(result.as_mut_ptr().add(i), vr);
967 i += 4;
968 }
969 }
970 }
971 }
972
973 while i < len {
975 result[i] = a[i] + b[i];
976 i += 1;
977 }
978 }
979
980 #[inline]
982 pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
983 debug_assert_eq!(a.len(), b.len());
984 debug_assert_eq!(a.len(), result.len());
985
986 let len = a.len();
987 let mut i = 0;
988
989 #[cfg(target_arch = "x86_64")]
991 {
992 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
993 unsafe {
994 while i + 8 <= len {
995 let va = _mm256_loadu_ps(a.as_ptr().add(i));
996 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
997 let vr = _mm256_mul_ps(va, vb);
998 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
999 i += 8;
1000 }
1001 }
1002 } else if is_x86_feature_detected!("sse") {
1003 unsafe {
1004 while i + 4 <= len {
1005 let va = _mm_loadu_ps(a.as_ptr().add(i));
1006 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1007 let vr = _mm_mul_ps(va, vb);
1008 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1009 i += 4;
1010 }
1011 }
1012 }
1013 }
1014
1015 #[cfg(target_arch = "aarch64")]
1017 {
1018 if std::arch::is_aarch64_feature_detected!("neon") {
1019 unsafe {
1020 while i + 4 <= len {
1021 let va = vld1q_f32(a.as_ptr().add(i));
1022 let vb = vld1q_f32(b.as_ptr().add(i));
1023 let vr = vmulq_f32(va, vb);
1024 vst1q_f32(result.as_mut_ptr().add(i), vr);
1025 i += 4;
1026 }
1027 }
1028 }
1029 }
1030
1031 while i < len {
1033 result[i] = a[i] * b[i];
1034 i += 1;
1035 }
1036 }
1037
1038 #[inline]
1040 pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
1041 debug_assert_eq!(a.len(), b.len());
1042 debug_assert_eq!(a.len(), c.len());
1043 debug_assert_eq!(a.len(), result.len());
1044
1045 let len = a.len();
1046 let mut i = 0;
1047
1048 #[cfg(target_arch = "x86_64")]
1050 {
1051 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1052 unsafe {
1053 while i + 8 <= len {
1054 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1055 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1056 let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1057 let vr = _mm256_fmadd_ps(va, vb, vc);
1058 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1059 i += 8;
1060 }
1061 }
1062 } else if is_x86_feature_detected!("sse") {
1063 unsafe {
1064 while i + 4 <= len {
1065 let va = _mm_loadu_ps(a.as_ptr().add(i));
1066 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1067 let vc = _mm_loadu_ps(c.as_ptr().add(i));
1068 let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1069 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1070 i += 4;
1071 }
1072 }
1073 }
1074 }
1075
1076 #[cfg(target_arch = "aarch64")]
1078 {
1079 if std::arch::is_aarch64_feature_detected!("neon") {
1080 unsafe {
1081 while i + 4 <= len {
1082 let va = vld1q_f32(a.as_ptr().add(i));
1083 let vb = vld1q_f32(b.as_ptr().add(i));
1084 let vc = vld1q_f32(c.as_ptr().add(i));
1085 let vr = vfmaq_f32(vc, va, vb);
1086 vst1q_f32(result.as_mut_ptr().add(i), vr);
1087 i += 4;
1088 }
1089 }
1090 }
1091 }
1092
1093 while i < len {
1095 result[i] = a[i] * b[i] + c[0];
1096 i += 1;
1097 }
1098 }
1099
1100 #[inline]
1102 pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1103 debug_assert_eq!(a.len(), b.len());
1104
1105 let len = a.len();
1106 let mut i = 0;
1107 let mut sum = 0.0f32;
1108
1109 #[cfg(target_arch = "x86_64")]
1111 {
1112 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1113 unsafe {
1114 let mut acc = _mm256_setzero_ps();
1115 while i + 8 <= len {
1116 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1117 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1118 acc = _mm256_fmadd_ps(va, vb, acc);
1119 i += 8;
1120 }
1121 let hi = _mm256_extractf128_ps(acc, 1);
1123 let lo = _mm256_castps256_ps128(acc);
1124 let sum4 = _mm_add_ps(hi, lo);
1125 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1126 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1127 sum = _mm_cvtss_f32(sum1);
1128 }
1129 } else if is_x86_feature_detected!("sse") {
1130 unsafe {
1131 let mut acc = _mm_setzero_ps();
1132 while i + 4 <= len {
1133 let va = _mm_loadu_ps(a.as_ptr().add(i));
1134 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1135 acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1136 i += 4;
1137 }
1138 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1140 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1141 sum = _mm_cvtss_f32(sum1);
1142 }
1143 }
1144 }
1145
1146 #[cfg(target_arch = "aarch64")]
1148 {
1149 if std::arch::is_aarch64_feature_detected!("neon") {
1150 unsafe {
1151 let mut acc = vdupq_n_f32(0.0);
1152 while i + 4 <= len {
1153 let va = vld1q_f32(a.as_ptr().add(i));
1154 let vb = vld1q_f32(b.as_ptr().add(i));
1155 acc = vfmaq_f32(acc, va, vb);
1156 i += 4;
1157 }
1158 sum = vaddvq_f32(acc);
1160 }
1161 }
1162 }
1163
1164 while i < len {
1166 sum += a[i] * b[i];
1167 i += 1;
1168 }
1169
1170 sum
1171 }
1172
1173 #[inline]
1175 pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1176 let len = data.len();
1177 let mut i = 0;
1178 let mut sum = 0.0f32;
1179
1180 #[cfg(target_arch = "x86_64")]
1182 {
1183 if is_x86_feature_detected!("avx2") {
1184 unsafe {
1185 let mut acc = _mm256_setzero_ps();
1186 while i + 8 <= len {
1187 let v = _mm256_loadu_ps(data.as_ptr().add(i));
1188 acc = _mm256_add_ps(acc, v);
1189 i += 8;
1190 }
1191 let hi = _mm256_extractf128_ps(acc, 1);
1193 let lo = _mm256_castps256_ps128(acc);
1194 let sum4 = _mm_add_ps(hi, lo);
1195 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1196 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1197 sum = _mm_cvtss_f32(sum1);
1198 }
1199 } else if is_x86_feature_detected!("sse") {
1200 unsafe {
1201 let mut acc = _mm_setzero_ps();
1202 while i + 4 <= len {
1203 let v = _mm_loadu_ps(data.as_ptr().add(i));
1204 acc = _mm_add_ps(acc, v);
1205 i += 4;
1206 }
1207 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1208 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1209 sum = _mm_cvtss_f32(sum1);
1210 }
1211 }
1212 }
1213
1214 #[cfg(target_arch = "aarch64")]
1216 {
1217 if std::arch::is_aarch64_feature_detected!("neon") {
1218 unsafe {
1219 let mut acc = vdupq_n_f32(0.0);
1220 while i + 4 <= len {
1221 let v = vld1q_f32(data.as_ptr().add(i));
1222 acc = vaddq_f32(acc, v);
1223 i += 4;
1224 }
1225 sum = vaddvq_f32(acc);
1226 }
1227 }
1228 }
1229
1230 while i < len {
1232 sum += data[i];
1233 i += 1;
1234 }
1235
1236 sum
1237 }
1238}
1239
1240#[cfg(test)]
1241mod tests {
1242 use super::*;
1243
1244 #[test]
1245 fn test_scientific_number_f32() {
1246 let a: f32 = 3.0;
1247 let b: f32 = 4.0;
1248
1249 assert_eq!(a.abs(), 3.0);
1250 assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1251 assert_eq!(a.square(), 9.0);
1252 assert_eq!(a.max(b), 4.0);
1253 assert_eq!(a.min(b), 3.0);
1254 assert!(a.is_finite());
1255 assert_eq!(a.to_f64(), Some(3.0));
1256 assert_eq!(<f32 as ScientificNumber>::from_f64(3.5), Some(3.5));
1257 }
1258
1259 #[test]
1260 fn test_scientific_number_f64() {
1261 let a: f64 = 3.0;
1262 let b: f64 = 4.0;
1263
1264 assert_eq!(a.abs(), 3.0);
1265 assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1266 assert_eq!(a.square(), 9.0);
1267 assert_eq!(a.max(b), 4.0);
1268 assert_eq!(a.min(b), 3.0);
1269 assert!(a.is_finite());
1270 assert_eq!(a.to_f64(), Some(3.0));
1271 assert_eq!(<f64 as ScientificNumber>::from_f64(3.5), Some(3.5));
1272 }
1273
1274 #[test]
1275 fn test_real_number_f32() {
1276 let a: f32 = 3.0;
1277
1278 assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1279 assert_eq!(a.exp(), (3.0_f32).exp());
1280 assert_eq!(a.ln(), (3.0_f32).ln());
1281 assert_eq!(a.sin(), (3.0_f32).sin());
1282 assert_eq!(a.cos(), (3.0_f32).cos());
1283 assert_eq!(a.powf(2.0), 9.0);
1284 }
1285
1286 #[test]
1287 fn test_real_number_f64() {
1288 let a: f64 = 3.0;
1289
1290 assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1291 assert_eq!(a.exp(), (3.0_f64).exp());
1292 assert_eq!(a.ln(), (3.0_f64).ln());
1293 assert_eq!(a.sin(), (3.0_f64).sin());
1294 assert_eq!(a.cos(), (3.0_f64).cos());
1295 assert_eq!(a.powf(2.0), 9.0);
1296 }
1297
1298 #[test]
1299 fn test_scientific_integer_i32() {
1300 let a: i32 = 12;
1301 let b: i32 = 8;
1302
1303 assert_eq!(a.gcd(b), 4);
1304 assert_eq!(a.lcm(b), 24);
1305 assert!(!a.is_prime());
1306 assert!(11_i32.is_prime());
1307 assert!(a.is_even());
1308 assert!(!a.is_odd());
1309 assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial().unwrap(), 120);
1311 assert_eq!(5_i32.binomial(2), 10); }
1313
1314 #[test]
1315 fn test_numeric_conversion() {
1316 let a: f64 = 3.5;
1317 let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1318 assert_eq!(b, 3);
1319
1320 let c: f32 = 100.5;
1321 let d: f64 = c.convert();
1322 assert_eq!(d, 100.5);
1323
1324 let e: i32 = 100;
1325 let f: f32 = e.convert();
1326 assert_eq!(f, 100.0);
1327 }
1328
1329 #[test]
1330 fn test_angle_conversion() {
1331 let degrees: f64 = 180.0;
1332 let radians = <f64 as AngleConversion>::to_radians(°rees).unwrap();
1333 assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1334
1335 let radians: f64 = std::f64::consts::PI / 2.0;
1336 let degrees = <f64 as AngleConversion>::to_degrees(&radians).unwrap();
1337 assert!((degrees - 90.0).abs() < 1e-10);
1338 }
1339
1340 #[test]
1341 fn test_scalar() {
1342 let a = Scalar::new(3.0_f64);
1343 let b = Scalar::new(4.0_f64);
1344
1345 assert_eq!((a + b).value(), 7.0);
1346 assert_eq!((a - b).value(), -1.0);
1347 assert_eq!((a * b).value(), 12.0);
1348 assert_eq!((a / b).value(), 0.75);
1349 assert_eq!((-a).value(), -3.0);
1350
1351 let c: Scalar<f64> = 5.0.into();
1352 assert_eq!(c.value(), 5.0);
1353 }
1354}