1use crate::error::{CoreError, CoreResult, ErrorContext};
7use num_traits::{Float, Num, NumCast, One, Zero};
8use std::fmt::Debug;
9use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
10
11pub trait ScientificNumber:
16 Num
17 + Clone
18 + Copy
19 + PartialOrd
20 + Debug
21 + Zero
22 + One
23 + Add<Output = Self>
24 + Sub<Output = Self>
25 + Mul<Output = Self>
26 + Div<Output = Self>
27 + AddAssign
28 + SubAssign
29 + MulAssign
30 + DivAssign
31 + NumCast
32{
33 #[must_use]
35 fn abs(self) -> Self;
36
37 #[must_use]
39 fn sqrt(self) -> Self;
40
41 #[must_use]
43 fn square(self) -> Self {
44 self * self
45 }
46
47 #[must_use]
49 fn max(self, other: Self) -> Self;
50
51 #[must_use]
53 fn min(self, other: Self) -> Self;
54
55 #[must_use]
57 fn is_finite(self) -> bool;
58
59 #[must_use]
61 fn to_f64(self) -> Option<f64>;
62
63 #[must_use]
65 fn from_f64(value: f64) -> Option<Self>;
66
67 #[must_use]
69 fn from_le_bytes(bytes: &[u8]) -> Self;
70
71 #[must_use]
73 fn from_be_bytes(bytes: &[u8]) -> Self;
74
75 #[must_use]
77 fn to_le_bytes(self) -> Vec<u8>;
78
79 #[must_use]
81 fn to_be_bytes(self) -> Vec<u8>;
82}
83
84pub trait RealNumber: ScientificNumber + Float {
86 #[must_use]
88 fn epsilon() -> Self;
89
90 #[must_use]
92 fn exp(self) -> Self;
93
94 #[must_use]
96 fn ln(self) -> Self;
97
98 #[must_use]
100 fn log10(self) -> Self;
101
102 #[must_use]
104 fn log2(self) -> Self;
105
106 #[must_use]
108 fn sin(self) -> Self;
109
110 #[must_use]
112 fn cos(self) -> Self;
113
114 #[must_use]
116 fn tan(self) -> Self;
117
118 #[must_use]
120 fn sinh(self) -> Self;
121
122 #[must_use]
124 fn cosh(self) -> Self;
125
126 #[must_use]
128 fn tanh(self) -> Self;
129
130 #[must_use]
132 fn asin(self) -> Self;
133
134 #[must_use]
136 fn acos(self) -> Self;
137
138 #[must_use]
140 fn atan(self) -> Self;
141
142 #[must_use]
144 fn atan2(self, other: Self) -> Self;
145
146 #[must_use]
148 fn powf(self, n: Self) -> Self;
149
150 #[must_use]
152 fn powi(self, n: i32) -> Self;
153
154 #[must_use]
156 fn factorial(self) -> Self;
157}
158
159pub trait ComplexNumber: ScientificNumber {
161 type RealPart: RealNumber;
163
164 #[must_use]
166 fn re(&self) -> Self::RealPart;
167
168 #[must_use]
170 fn im(&self) -> Self::RealPart;
171
172 #[must_use]
174 fn from_parts(re: Self::RealPart, im: Self::RealPart) -> Self;
175
176 #[must_use]
178 fn conj(self) -> Self;
179
180 #[must_use]
182 fn abs(self) -> Self::RealPart;
183
184 #[must_use]
186 fn arg(self) -> Self::RealPart;
187
188 #[must_use]
190 fn to_polar(self) -> (Self::RealPart, Self::RealPart);
191
192 #[must_use]
194 fn from_polar(r: Self::RealPart, theta: Self::RealPart) -> Self;
195
196 #[must_use]
198 fn exp(self) -> Self;
199
200 #[must_use]
202 fn ln(self) -> Self;
203
204 #[must_use]
206 fn powc(self, exp: Self) -> Self;
207
208 #[must_use]
210 fn powf(self, exp: Self::RealPart) -> Self;
211
212 #[must_use]
214 fn sqrt(self) -> Self;
215}
216
217pub trait ScientificInteger: ScientificNumber + Eq {
219 #[must_use]
221 fn gcd(self, other: Self) -> Self;
222
223 #[must_use]
225 fn lcm(self, other: Self) -> Self;
226
227 #[must_use]
229 fn is_prime(self) -> bool;
230
231 #[must_use]
233 fn is_even(self) -> bool;
234
235 #[must_use]
237 fn is_odd(self) -> bool;
238
239 #[must_use]
241 fn mod_pow(self, exp: Self, modulus: Self) -> Self;
242
243 fn factorial(self) -> CoreResult<Self>;
245
246 #[must_use]
248 fn binomial(self, k: Self) -> Self;
249}
250
251impl ScientificNumber for f32 {
253 fn abs(self) -> Self {
254 self.abs()
255 }
256
257 fn sqrt(self) -> Self {
258 self.sqrt()
259 }
260
261 fn max(self, other: Self) -> Self {
262 self.max(other)
263 }
264
265 fn min(self, other: Self) -> Self {
266 self.min(other)
267 }
268
269 fn is_finite(self) -> bool {
270 self.is_finite()
271 }
272
273 fn to_f64(self) -> Option<f64> {
274 Some(self as f64)
275 }
276
277 fn from_f64(value: f64) -> Option<Self> {
278 if value.is_finite() && value <= Self::MAX as f64 && value >= Self::MIN as f64 {
279 Some(value as f32)
280 } else {
281 None
282 }
283 }
284
285 fn from_le_bytes(bytes: &[u8]) -> Self {
286 let mut array = [0u8; 4];
287 array.copy_from_slice(&bytes[..4]);
288 f32::from_le_bytes(array)
289 }
290
291 fn from_be_bytes(bytes: &[u8]) -> Self {
292 let mut array = [0u8; 4];
293 array.copy_from_slice(&bytes[..4]);
294 f32::from_be_bytes(array)
295 }
296
297 fn to_le_bytes(self) -> Vec<u8> {
298 self.to_le_bytes().to_vec()
299 }
300
301 fn to_be_bytes(self) -> Vec<u8> {
302 self.to_be_bytes().to_vec()
303 }
304}
305
306impl RealNumber for f32 {
308 fn epsilon() -> Self {
309 Self::EPSILON
310 }
311
312 fn exp(self) -> Self {
313 self.exp()
314 }
315
316 fn ln(self) -> Self {
317 self.ln()
318 }
319
320 fn log10(self) -> Self {
321 self.log10()
322 }
323
324 fn log2(self) -> Self {
325 self.log2()
326 }
327
328 fn sin(self) -> Self {
329 self.sin()
330 }
331
332 fn cos(self) -> Self {
333 self.cos()
334 }
335
336 fn tan(self) -> Self {
337 self.tan()
338 }
339
340 fn sinh(self) -> Self {
341 self.sinh()
342 }
343
344 fn cosh(self) -> Self {
345 self.cosh()
346 }
347
348 fn tanh(self) -> Self {
349 self.tanh()
350 }
351
352 fn asin(self) -> Self {
353 self.asin()
354 }
355
356 fn acos(self) -> Self {
357 self.acos()
358 }
359
360 fn atan(self) -> Self {
361 self.atan()
362 }
363
364 fn atan2(self, other: Self) -> Self {
365 self.atan2(other)
366 }
367
368 fn powf(self, n: Self) -> Self {
369 self.powf(n)
370 }
371
372 fn powi(self, n: i32) -> Self {
373 self.powi(n)
374 }
375
376 fn factorial(self) -> Self {
377 if self < 0.0 {
378 return Self::NAN;
379 }
380
381 if self != self.trunc() || self > 100.0 {
383 const SQRT_TWO_PI: f32 = 2.506_628_3;
384 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
385 }
386
387 let mut result = 1.0;
388 let n = self as u32;
389 for i in 2..=n {
390 result *= i as f32;
391 }
392
393 result
394 }
395}
396
397impl ScientificNumber for f64 {
399 fn abs(self) -> Self {
400 self.abs()
401 }
402
403 fn sqrt(self) -> Self {
404 self.sqrt()
405 }
406
407 fn max(self, other: Self) -> Self {
408 self.max(other)
409 }
410
411 fn min(self, other: Self) -> Self {
412 self.min(other)
413 }
414
415 fn is_finite(self) -> bool {
416 self.is_finite()
417 }
418
419 fn to_f64(self) -> Option<f64> {
420 Some(self)
421 }
422
423 fn from_f64(value: f64) -> Option<Self> {
424 Some(value)
425 }
426
427 fn from_le_bytes(bytes: &[u8]) -> Self {
428 let mut array = [0u8; 8];
429 array.copy_from_slice(&bytes[..8]);
430 f64::from_le_bytes(array)
431 }
432
433 fn from_be_bytes(bytes: &[u8]) -> Self {
434 let mut array = [0u8; 8];
435 array.copy_from_slice(&bytes[..8]);
436 f64::from_be_bytes(array)
437 }
438
439 fn to_le_bytes(self) -> Vec<u8> {
440 self.to_le_bytes().to_vec()
441 }
442
443 fn to_be_bytes(self) -> Vec<u8> {
444 self.to_be_bytes().to_vec()
445 }
446}
447
448impl RealNumber for f64 {
450 fn epsilon() -> Self {
451 Self::EPSILON
452 }
453
454 fn exp(self) -> Self {
455 self.exp()
456 }
457
458 fn ln(self) -> Self {
459 self.ln()
460 }
461
462 fn log10(self) -> Self {
463 self.log10()
464 }
465
466 fn log2(self) -> Self {
467 self.log2()
468 }
469
470 fn sin(self) -> Self {
471 self.sin()
472 }
473
474 fn cos(self) -> Self {
475 self.cos()
476 }
477
478 fn tan(self) -> Self {
479 self.tan()
480 }
481
482 fn sinh(self) -> Self {
483 self.sinh()
484 }
485
486 fn cosh(self) -> Self {
487 self.cosh()
488 }
489
490 fn tanh(self) -> Self {
491 self.tanh()
492 }
493
494 fn asin(self) -> Self {
495 self.asin()
496 }
497
498 fn acos(self) -> Self {
499 self.acos()
500 }
501
502 fn atan(self) -> Self {
503 self.atan()
504 }
505
506 fn atan2(self, other: Self) -> Self {
507 self.atan2(other)
508 }
509
510 fn powf(self, n: Self) -> Self {
511 self.powf(n)
512 }
513
514 fn powi(self, n: i32) -> Self {
515 self.powi(n)
516 }
517
518 fn factorial(self) -> Self {
519 if self < 0.0 {
520 return Self::NAN;
521 }
522
523 if self != self.trunc() || self > 170.0 {
525 const SQRT_TWO_PI: f64 = 2.506_628_274_631_000_2;
526 return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
527 }
528
529 let mut result = 1.0;
530 let n = self as u32;
531 for i in 2..=n {
532 result *= i as f64;
533 }
534
535 result
536 }
537}
538
539impl ScientificNumber for i32 {
541 fn abs(self) -> Self {
542 self.abs()
543 }
544
545 fn sqrt(self) -> Self {
546 (self as f64).sqrt() as i32
547 }
548
549 fn max(self, other: Self) -> Self {
550 std::cmp::max(self, other)
551 }
552
553 fn min(self, other: Self) -> Self {
554 std::cmp::min(self, other)
555 }
556
557 fn is_finite(self) -> bool {
558 true }
560
561 fn to_f64(self) -> Option<f64> {
562 Some(self as f64)
563 }
564
565 fn from_f64(value: f64) -> Option<Self> {
566 if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
567 Some(value as i32)
568 } else {
569 None
570 }
571 }
572
573 fn from_le_bytes(bytes: &[u8]) -> Self {
574 let mut array = [0u8; 4];
575 array.copy_from_slice(&bytes[..4]);
576 i32::from_le_bytes(array)
577 }
578
579 fn from_be_bytes(bytes: &[u8]) -> Self {
580 let mut array = [0u8; 4];
581 array.copy_from_slice(&bytes[..4]);
582 i32::from_be_bytes(array)
583 }
584
585 fn to_le_bytes(self) -> Vec<u8> {
586 self.to_le_bytes().to_vec()
587 }
588
589 fn to_be_bytes(self) -> Vec<u8> {
590 self.to_be_bytes().to_vec()
591 }
592}
593
594impl ScientificInteger for i32 {
596 fn gcd(self, other: Self) -> Self {
597 let mut a = self.abs();
598 let mut b = other.abs();
599
600 if a == 0 {
601 return b;
602 }
603 if b == 0 {
604 return a;
605 }
606
607 while b != 0 {
608 let temp = b;
609 b = a % b;
610 a = temp;
611 }
612
613 a
614 }
615
616 fn lcm(self, other: Self) -> Self {
617 if self == 0 || other == 0 {
618 return 0;
619 }
620
621 let gcd = self.gcd(other);
622
623 (self / gcd) * other
624 }
625
626 fn is_prime(self) -> bool {
627 if self <= 1 {
628 return false;
629 }
630 if self <= 3 {
631 return true;
632 }
633 if self % 2 == 0 || self % 3 == 0 {
634 return false;
635 }
636
637 let mut i = 5;
638 while i * i <= self {
639 if self % i == 0 || self % (i + 2) == 0 {
640 return false;
641 }
642 i += 6;
643 }
644
645 true
646 }
647
648 fn is_even(self) -> bool {
649 self % 2 == 0
650 }
651
652 fn is_odd(self) -> bool {
653 self % 2 != 0
654 }
655
656 fn mod_pow(self, exp: Self, modulus: Self) -> Self {
657 if modulus == 1 {
658 return 0;
659 }
660
661 let mut base = self % modulus;
662 let mut result = 1;
663 let mut exponent = exp;
664
665 while exponent > 0 {
666 if exponent % 2 == 1 {
667 result = (result * base) % modulus;
668 }
669 exponent >>= 1;
670 base = (base * base) % modulus;
671 }
672
673 result
674 }
675
676 fn factorial(self) -> CoreResult<Self> {
677 if self < 0 {
678 return Err(CoreError::ValueError(ErrorContext::new(
679 "Factorial not defined for negative numbers".to_string(),
680 )));
681 }
682
683 let mut result = 1;
684 for i in 2..=self {
685 result *= i;
686 }
687
688 Ok(result)
689 }
690
691 fn binomial(self, k: Self) -> Self {
692 if k < 0 || k > self {
693 return 0;
694 }
695
696 let k = std::cmp::min(k, self - k);
697 let mut result = 1;
698
699 for i in 0..k {
700 result = result * (self - i) / (i + 1);
701 }
702
703 result
704 }
705}
706
707pub trait NumericConversion<T> {
709 fn try_convert(self) -> Option<T>;
711
712 fn convert_or(self, default: T) -> T;
714
715 fn convert(self) -> T;
717}
718
719impl<F, T> NumericConversion<T> for F
721where
722 F: NumCast,
723 T: NumCast,
724{
725 fn try_convert(self) -> Option<T> {
726 num_traits::cast(self)
727 }
728
729 fn convert_or(self, default: T) -> T {
730 self.try_convert().unwrap_or(default)
731 }
732
733 fn convert(self) -> T {
734 self.try_convert().expect("Numeric conversion failed")
735 }
736}
737
738pub trait AngleConversion: Sized {
740 fn to_radians(&self) -> CoreResult<Self>
742 where
743 Self: std::marker::Sized;
744
745 fn to_degrees(&self) -> CoreResult<Self>
747 where
748 Self: std::marker::Sized;
749}
750
751impl<T: RealNumber> AngleConversion for T {
753 fn to_radians(&self) -> CoreResult<Self> {
754 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
755 CoreError::ValueError(ErrorContext::new(
756 "Failed to convert PI constant to target type".to_string(),
757 ))
758 })?;
759 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
760 CoreError::ValueError(ErrorContext::new(
761 "Failed to convert 180.0 to target type".to_string(),
762 ))
763 })?;
764 Ok(*self * pi / one_eighty)
765 }
766
767 fn to_degrees(&self) -> CoreResult<Self> {
768 let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
769 CoreError::ValueError(ErrorContext::new(
770 "Failed to convert PI constant to target type".to_string(),
771 ))
772 })?;
773 let one_eighty = T::from_f64(180.0).ok_or_else(|| {
774 CoreError::ValueError(ErrorContext::new(
775 "Failed to convert 180.0 to target type".to_string(),
776 ))
777 })?;
778 Ok(*self * one_eighty / pi)
779 }
780}
781
782#[derive(Clone, Copy, PartialEq, Debug)]
784pub struct Scalar<T: ScientificNumber>(pub T);
785
786impl<T: ScientificNumber> Scalar<T> {
787 pub fn new(value: T) -> Self {
789 Scalar(value)
790 }
791
792 pub fn value(&self) -> T {
794 self.0
795 }
796}
797
798impl<T: ScientificNumber> From<T> for Scalar<T> {
799 fn from(value: T) -> Self {
800 Scalar(value)
801 }
802}
803
804impl<T: ScientificNumber> Add for Scalar<T> {
805 type Output = Self;
806
807 fn add(self, other: Self) -> Self::Output {
808 Scalar(self.0 + other.0)
809 }
810}
811
812impl<T: ScientificNumber> Sub for Scalar<T> {
813 type Output = Self;
814
815 fn sub(self, other: Self) -> Self::Output {
816 Scalar(self.0 - other.0)
817 }
818}
819
820impl<T: ScientificNumber> Mul for Scalar<T> {
821 type Output = Self;
822
823 fn mul(self, other: Self) -> Self::Output {
824 Scalar(self.0 * other.0)
825 }
826}
827
828impl<T: ScientificNumber> Div for Scalar<T> {
829 type Output = Self;
830
831 fn div(self, other: Self) -> Self::Output {
832 Scalar(self.0 / other.0)
833 }
834}
835
836impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
837 type Output = Self;
838
839 fn neg(self) -> Self::Output {
840 Scalar(self.0.neg())
841 }
842}
843
844pub mod precision_tracking;
846
847pub mod scientific_types;
849
850#[cfg(feature = "arbitrary-precision")]
852pub mod arbitrary_precision;
853
854pub mod stability;
856
857pub mod stable_algorithms;
859
860pub mod advanced_simd {
865 #[allow(unused_imports)]
866 use super::*;
867
868 #[cfg(target_arch = "aarch64")]
869 use std::arch::aarch64::*;
870 #[cfg(target_arch = "x86_64")]
871 use std::arch::x86_64::*;
872
873 #[inline]
875 pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
876 debug_assert_eq!(a.len(), b.len());
877 debug_assert_eq!(a.len(), result.len());
878
879 let len = a.len();
880 let mut i = 0;
881
882 #[cfg(target_arch = "x86_64")]
884 {
885 if is_x86_feature_detected!("avx2") {
886 unsafe {
887 while i + 8 <= len {
888 let va = _mm256_loadu_ps(a.as_ptr().add(i));
889 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
890 let vr = _mm256_add_ps(va, vb);
891 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
892 i += 8;
893 }
894 }
895 }
896 else if is_x86_feature_detected!("sse") {
898 unsafe {
899 while i + 4 <= len {
900 let va = _mm_loadu_ps(a.as_ptr().add(i));
901 let vb = _mm_loadu_ps(b.as_ptr().add(i));
902 let vr = _mm_add_ps(va, vb);
903 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
904 i += 4;
905 }
906 }
907 }
908 }
909
910 #[cfg(target_arch = "aarch64")]
912 {
913 if std::arch::is_aarch64_feature_detected!("neon") {
914 unsafe {
915 while i + 4 <= len {
916 let va = vld1q_f32(a.as_ptr().add(i));
917 let vb = vld1q_f32(b.as_ptr().add(i));
918 let vr = vaddq_f32(va, vb);
919 vst1q_f32(result.as_mut_ptr().add(i), vr);
920 i += 4;
921 }
922 }
923 }
924 }
925
926 while i < len {
928 result[i] = a[i] + b[i];
929 i += 1;
930 }
931 }
932
933 #[inline]
935 pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
936 debug_assert_eq!(a.len(), b.len());
937 debug_assert_eq!(a.len(), result.len());
938
939 let len = a.len();
940 let mut i = 0;
941
942 #[cfg(target_arch = "x86_64")]
944 {
945 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
946 unsafe {
947 while i + 8 <= len {
948 let va = _mm256_loadu_ps(a.as_ptr().add(i));
949 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
950 let vr = _mm256_mul_ps(va, vb);
951 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
952 i += 8;
953 }
954 }
955 } else if is_x86_feature_detected!("sse") {
956 unsafe {
957 while i + 4 <= len {
958 let va = _mm_loadu_ps(a.as_ptr().add(i));
959 let vb = _mm_loadu_ps(b.as_ptr().add(i));
960 let vr = _mm_mul_ps(va, vb);
961 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
962 i += 4;
963 }
964 }
965 }
966 }
967
968 #[cfg(target_arch = "aarch64")]
970 {
971 if std::arch::is_aarch64_feature_detected!("neon") {
972 unsafe {
973 while i + 4 <= len {
974 let va = vld1q_f32(a.as_ptr().add(i));
975 let vb = vld1q_f32(b.as_ptr().add(i));
976 let vr = vmulq_f32(va, vb);
977 vst1q_f32(result.as_mut_ptr().add(i), vr);
978 i += 4;
979 }
980 }
981 }
982 }
983
984 while i < len {
986 result[i] = a[i] * b[i];
987 i += 1;
988 }
989 }
990
991 #[inline]
993 pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
994 debug_assert_eq!(a.len(), b.len());
995 debug_assert_eq!(a.len(), c.len());
996 debug_assert_eq!(a.len(), result.len());
997
998 let len = a.len();
999 let mut i = 0;
1000
1001 #[cfg(target_arch = "x86_64")]
1003 {
1004 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1005 unsafe {
1006 while i + 8 <= len {
1007 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1008 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1009 let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1010 let vr = _mm256_fmadd_ps(va, vb, vc);
1011 _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1012 i += 8;
1013 }
1014 }
1015 } else if is_x86_feature_detected!("sse") {
1016 unsafe {
1017 while i + 4 <= len {
1018 let va = _mm_loadu_ps(a.as_ptr().add(i));
1019 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1020 let vc = _mm_loadu_ps(c.as_ptr().add(i));
1021 let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1022 _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1023 i += 4;
1024 }
1025 }
1026 }
1027 }
1028
1029 #[cfg(target_arch = "aarch64")]
1031 {
1032 if std::arch::is_aarch64_feature_detected!("neon") {
1033 unsafe {
1034 while i + 4 <= len {
1035 let va = vld1q_f32(a.as_ptr().add(i));
1036 let vb = vld1q_f32(b.as_ptr().add(i));
1037 let vc = vld1q_f32(c.as_ptr().add(i));
1038 let vr = vfmaq_f32(vc, va, vb);
1039 vst1q_f32(result.as_mut_ptr().add(i), vr);
1040 i += 4;
1041 }
1042 }
1043 }
1044 }
1045
1046 while i < len {
1048 result[i] = a[i] * b[i] + c[0];
1049 i += 1;
1050 }
1051 }
1052
1053 #[inline]
1055 pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1056 debug_assert_eq!(a.len(), b.len());
1057
1058 let len = a.len();
1059 let mut i = 0;
1060 let mut sum = 0.0f32;
1061
1062 #[cfg(target_arch = "x86_64")]
1064 {
1065 if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1066 unsafe {
1067 let mut acc = _mm256_setzero_ps();
1068 while i + 8 <= len {
1069 let va = _mm256_loadu_ps(a.as_ptr().add(i));
1070 let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1071 acc = _mm256_fmadd_ps(va, vb, acc);
1072 i += 8;
1073 }
1074 let hi = _mm256_extractf128_ps(acc, 1);
1076 let lo = _mm256_castps256_ps128(acc);
1077 let sum4 = _mm_add_ps(hi, lo);
1078 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1079 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1080 sum = _mm_cvtss_f32(sum1);
1081 }
1082 } else if is_x86_feature_detected!("sse") {
1083 unsafe {
1084 let mut acc = _mm_setzero_ps();
1085 while i + 4 <= len {
1086 let va = _mm_loadu_ps(a.as_ptr().add(i));
1087 let vb = _mm_loadu_ps(b.as_ptr().add(i));
1088 acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1089 i += 4;
1090 }
1091 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1093 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1094 sum = _mm_cvtss_f32(sum1);
1095 }
1096 }
1097 }
1098
1099 #[cfg(target_arch = "aarch64")]
1101 {
1102 if std::arch::is_aarch64_feature_detected!("neon") {
1103 unsafe {
1104 let mut acc = vdupq_n_f32(0.0);
1105 while i + 4 <= len {
1106 let va = vld1q_f32(a.as_ptr().add(i));
1107 let vb = vld1q_f32(b.as_ptr().add(i));
1108 acc = vfmaq_f32(acc, va, vb);
1109 i += 4;
1110 }
1111 sum = vaddvq_f32(acc);
1113 }
1114 }
1115 }
1116
1117 while i < len {
1119 sum += a[i] * b[i];
1120 i += 1;
1121 }
1122
1123 sum
1124 }
1125
1126 #[inline]
1128 pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1129 let len = data.len();
1130 let mut i = 0;
1131 let mut sum = 0.0f32;
1132
1133 #[cfg(target_arch = "x86_64")]
1135 {
1136 if is_x86_feature_detected!("avx2") {
1137 unsafe {
1138 let mut acc = _mm256_setzero_ps();
1139 while i + 8 <= len {
1140 let v = _mm256_loadu_ps(data.as_ptr().add(i));
1141 acc = _mm256_add_ps(acc, v);
1142 i += 8;
1143 }
1144 let hi = _mm256_extractf128_ps(acc, 1);
1146 let lo = _mm256_castps256_ps128(acc);
1147 let sum4 = _mm_add_ps(hi, lo);
1148 let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1149 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1150 sum = _mm_cvtss_f32(sum1);
1151 }
1152 } else if is_x86_feature_detected!("sse") {
1153 unsafe {
1154 let mut acc = _mm_setzero_ps();
1155 while i + 4 <= len {
1156 let v = _mm_loadu_ps(data.as_ptr().add(i));
1157 acc = _mm_add_ps(acc, v);
1158 i += 4;
1159 }
1160 let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1161 let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1162 sum = _mm_cvtss_f32(sum1);
1163 }
1164 }
1165 }
1166
1167 #[cfg(target_arch = "aarch64")]
1169 {
1170 if std::arch::is_aarch64_feature_detected!("neon") {
1171 unsafe {
1172 let mut acc = vdupq_n_f32(0.0);
1173 while i + 4 <= len {
1174 let v = vld1q_f32(data.as_ptr().add(i));
1175 acc = vaddq_f32(acc, v);
1176 i += 4;
1177 }
1178 sum = vaddvq_f32(acc);
1179 }
1180 }
1181 }
1182
1183 while i < len {
1185 sum += data[i];
1186 i += 1;
1187 }
1188
1189 sum
1190 }
1191}
1192
1193#[cfg(test)]
1194mod tests {
1195 use super::*;
1196
1197 #[test]
1198 fn test_scientific_number_f32() {
1199 let a: f32 = 3.0;
1200 let b: f32 = 4.0;
1201
1202 assert_eq!(a.abs(), 3.0);
1203 assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1204 assert_eq!(a.square(), 9.0);
1205 assert_eq!(a.max(b), 4.0);
1206 assert_eq!(a.min(b), 3.0);
1207 assert!(a.is_finite());
1208 assert_eq!(a.to_f64(), Some(3.0));
1209 assert_eq!(f32::from_f64(3.5), Some(3.5));
1210 }
1211
1212 #[test]
1213 fn test_scientific_number_f64() {
1214 let a: f64 = 3.0;
1215 let b: f64 = 4.0;
1216
1217 assert_eq!(a.abs(), 3.0);
1218 assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1219 assert_eq!(a.square(), 9.0);
1220 assert_eq!(a.max(b), 4.0);
1221 assert_eq!(a.min(b), 3.0);
1222 assert!(a.is_finite());
1223 assert_eq!(a.to_f64(), Some(3.0));
1224 assert_eq!(f64::from_f64(3.5), Some(3.5));
1225 }
1226
1227 #[test]
1228 fn test_real_number_f32() {
1229 let a: f32 = 3.0;
1230
1231 assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1232 assert_eq!(a.exp(), (3.0_f32).exp());
1233 assert_eq!(a.ln(), (3.0_f32).ln());
1234 assert_eq!(a.sin(), (3.0_f32).sin());
1235 assert_eq!(a.cos(), (3.0_f32).cos());
1236 assert_eq!(a.powf(2.0), 9.0);
1237 }
1238
1239 #[test]
1240 fn test_real_number_f64() {
1241 let a: f64 = 3.0;
1242
1243 assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1244 assert_eq!(a.exp(), (3.0_f64).exp());
1245 assert_eq!(a.ln(), (3.0_f64).ln());
1246 assert_eq!(a.sin(), (3.0_f64).sin());
1247 assert_eq!(a.cos(), (3.0_f64).cos());
1248 assert_eq!(a.powf(2.0), 9.0);
1249 }
1250
1251 #[test]
1252 fn test_scientific_integer_i32() {
1253 let a: i32 = 12;
1254 let b: i32 = 8;
1255
1256 assert_eq!(a.gcd(b), 4);
1257 assert_eq!(a.lcm(b), 24);
1258 assert!(!a.is_prime());
1259 assert!(11_i32.is_prime());
1260 assert!(a.is_even());
1261 assert!(!a.is_odd());
1262 assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial().unwrap(), 120);
1264 assert_eq!(5_i32.binomial(2), 10); }
1266
1267 #[test]
1268 fn test_numeric_conversion() {
1269 let a: f64 = 3.5;
1270 let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1271 assert_eq!(b, 3);
1272
1273 let c: f32 = 100.5;
1274 let d: f64 = c.convert();
1275 assert_eq!(d, 100.5);
1276
1277 let e: i32 = 100;
1278 let f: f32 = e.convert();
1279 assert_eq!(f, 100.0);
1280 }
1281
1282 #[test]
1283 fn test_angle_conversion() {
1284 let degrees: f64 = 180.0;
1285 let radians = <f64 as AngleConversion>::to_radians(°rees).unwrap();
1286 assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1287
1288 let radians: f64 = std::f64::consts::PI / 2.0;
1289 let degrees = <f64 as AngleConversion>::to_degrees(&radians).unwrap();
1290 assert!((degrees - 90.0).abs() < 1e-10);
1291 }
1292
1293 #[test]
1294 fn test_scalar() {
1295 let a = Scalar::new(3.0_f64);
1296 let b = Scalar::new(4.0_f64);
1297
1298 assert_eq!((a + b).value(), 7.0);
1299 assert_eq!((a - b).value(), -1.0);
1300 assert_eq!((a * b).value(), 12.0);
1301 assert_eq!((a / b).value(), 0.75);
1302 assert_eq!((-a).value(), -3.0);
1303
1304 let c: Scalar<f64> = 5.0.into();
1305 assert_eq!(c.value(), 5.0);
1306 }
1307}