1use super::traits::MathBackend;
4
5#[cfg(feature = "floating-point")]
7pub struct FloatingPointBackend;
8
9#[cfg(feature = "floating-point")]
10impl MathBackend<f32> for FloatingPointBackend {
11 #[inline]
12 fn sqrt(&self, x: f32) -> f32 {
13 micromath::F32Ext::sqrt(x)
14 }
15
16 #[inline]
17 fn abs(&self, x: f32) -> f32 {
18 if x < 0.0 {
19 -x
20 } else {
21 x
22 }
23 }
24
25 #[inline]
26 fn min(&self, a: f32, b: f32) -> f32 {
27 if a < b {
28 a
29 } else {
30 b
31 }
32 }
33
34 #[inline]
35 fn max(&self, a: f32, b: f32) -> f32 {
36 if a > b {
37 a
38 } else {
39 b
40 }
41 }
42
43 #[inline]
44 fn floor(&self, x: f32) -> f32 {
45 micromath::F32Ext::floor(x)
46 }
47
48 #[inline]
49 fn ceil(&self, x: f32) -> f32 {
50 micromath::F32Ext::ceil(x)
51 }
52
53 #[inline]
54 fn pow(&self, x: f32, y: f32) -> f32 {
55 micromath::F32Ext::powf(x, y)
56 }
57
58 #[inline]
59 fn ln(&self, x: f32) -> f32 {
60 micromath::F32Ext::ln(x)
61 }
62
63 #[inline]
64 fn log10(&self, x: f32) -> f32 {
65 micromath::F32Ext::log10(x)
66 }
67
68 #[inline]
69 fn sin(&self, x: f32) -> f32 {
70 micromath::F32Ext::sin(x)
71 }
72
73 #[inline]
74 fn cos(&self, x: f32) -> f32 {
75 micromath::F32Ext::cos(x)
76 }
77
78 #[inline]
79 fn tan(&self, x: f32) -> f32 {
80 micromath::F32Ext::tan(x)
81 }
82
83 #[inline]
84 fn to_radians(&self, degrees: f32) -> f32 {
85 degrees * (core::f32::consts::PI / 180.0)
86 }
87
88 #[inline]
89 fn to_degrees(&self, radians: f32) -> f32 {
90 radians * (180.0 / core::f32::consts::PI)
91 }
92
93 #[inline]
94 fn atan2(&self, y: f32, x: f32) -> f32 {
95 micromath::F32Ext::atan2(y, x)
96 }
97}
98
99#[cfg(feature = "libm-math")]
101pub struct LibmBackend;
102
103#[cfg(feature = "libm-math")]
104impl MathBackend<f32> for LibmBackend {
105 #[inline]
106 fn sqrt(&self, x: f32) -> f32 {
107 libm::sqrtf(x)
108 }
109
110 #[inline]
111 fn abs(&self, x: f32) -> f32 {
112 libm::fabsf(x)
113 }
114
115 #[inline]
116 fn min(&self, a: f32, b: f32) -> f32 {
117 libm::fminf(a, b)
118 }
119
120 #[inline]
121 fn max(&self, a: f32, b: f32) -> f32 {
122 libm::fmaxf(a, b)
123 }
124
125 #[inline]
126 fn floor(&self, x: f32) -> f32 {
127 libm::floorf(x)
128 }
129
130 #[inline]
131 fn ceil(&self, x: f32) -> f32 {
132 libm::ceilf(x)
133 }
134
135 #[inline]
136 fn pow(&self, x: f32, y: f32) -> f32 {
137 libm::powf(x, y)
138 }
139
140 #[inline]
141 fn ln(&self, x: f32) -> f32 {
142 libm::logf(x)
143 }
144
145 #[inline]
146 fn log10(&self, x: f32) -> f32 {
147 libm::log10f(x)
148 }
149
150 #[inline]
151 fn sin(&self, x: f32) -> f32 {
152 libm::sinf(x)
153 }
154
155 #[inline]
156 fn cos(&self, x: f32) -> f32 {
157 libm::cosf(x)
158 }
159
160 #[inline]
161 fn tan(&self, x: f32) -> f32 {
162 libm::tanf(x)
163 }
164
165 #[inline]
166 fn to_radians(&self, degrees: f32) -> f32 {
167 degrees * (core::f32::consts::PI / 180.0)
168 }
169
170 #[inline]
171 fn to_degrees(&self, radians: f32) -> f32 {
172 radians * (180.0 / core::f32::consts::PI)
173 }
174
175 #[inline]
176 fn atan2(&self, y: f32, x: f32) -> f32 {
177 libm::atan2f(y, x)
178 }
179}
180
181#[cfg(any(feature = "fixed-point", feature = "cordic-math"))]
183pub struct FixedPointBackend;
184
185#[cfg(any(feature = "fixed-point", feature = "cordic-math"))]
186impl MathBackend<fixed::types::I16F16> for FixedPointBackend {
187 #[inline]
188 fn sqrt(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
189 if x <= fixed::types::I16F16::ZERO {
191 return fixed::types::I16F16::ZERO;
192 }
193
194 let mut guess = x / 2;
195 for _ in 0..8 {
196 let new_guess = (guess + x / guess) / 2;
198 if (new_guess - guess).abs() < fixed::types::I16F16::from_num(0.001) {
199 break;
200 }
201 guess = new_guess;
202 }
203 guess
204 }
205
206 #[inline]
207 fn abs(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
208 x.abs()
209 }
210
211 #[inline]
212 fn min(&self, a: fixed::types::I16F16, b: fixed::types::I16F16) -> fixed::types::I16F16 {
213 if a < b {
214 a
215 } else {
216 b
217 }
218 }
219
220 #[inline]
221 fn max(&self, a: fixed::types::I16F16, b: fixed::types::I16F16) -> fixed::types::I16F16 {
222 if a > b {
223 a
224 } else {
225 b
226 }
227 }
228
229 #[inline]
230 fn floor(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
231 x.floor()
232 }
233
234 #[inline]
235 fn ceil(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
236 x.ceil()
237 }
238
239 #[inline]
240 fn pow(&self, x: fixed::types::I16F16, y: fixed::types::I16F16) -> fixed::types::I16F16 {
241 if y == fixed::types::I16F16::ZERO {
243 return fixed::types::I16F16::ONE;
244 }
245
246 let y_int: i32 = y.to_num();
247 if y_int < 0 {
248 return fixed::types::I16F16::ONE / self.pow(x, -y);
249 }
250
251 let mut result = fixed::types::I16F16::ONE;
252 let mut base = x;
253 let mut exp = y_int as u32;
254
255 while exp > 0 {
256 if exp & 1 == 1 {
257 result *= base;
258 }
259 base = base * base;
260 exp >>= 1;
261 }
262 result
263 }
264
265 #[inline]
266 fn ln(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
267 if x <= fixed::types::I16F16::ZERO {
269 return fixed::types::I16F16::from_num(-100.0); }
271
272 let one = fixed::types::I16F16::ONE;
274 let t = x - one;
275
276 let t2 = t * t;
278 let t3 = t2 * t;
279 let t4 = t3 * t;
280
281 t - t2 / 2 + t3 / 3 - t4 / 4
282 }
283
284 #[inline]
285 fn log10(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
286 let ln_x = self.ln(x);
288 let ln_10 = fixed::types::I16F16::from_num(core::f32::consts::LN_10); ln_x / ln_10
290 }
291
292 #[inline]
293 fn sin(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
294 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
296 let two_pi = pi * 2;
297
298 let mut angle = x;
300 while angle > pi {
301 angle -= two_pi;
302 }
303 while angle < -pi {
304 angle += two_pi;
305 }
306
307 let x2 = angle * angle;
309 let x3 = x2 * angle;
310 let x5 = x3 * x2;
311 let x7 = x5 * x2;
312
313 angle - x3 / 6 + x5 / 120 - x7 / 5040
314 }
315
316 #[inline]
317 fn cos(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
318 let pi_2 = fixed::types::I16F16::from_num(core::f32::consts::FRAC_PI_2); self.sin(x + pi_2)
321 }
322
323 #[inline]
324 fn tan(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
325 let sin_x = self.sin(x);
327 let cos_x = self.cos(x);
328
329 if cos_x.abs() < fixed::types::I16F16::from_num(0.001) {
330 if sin_x >= fixed::types::I16F16::ZERO {
332 fixed::types::I16F16::from_num(100.0) } else {
334 fixed::types::I16F16::from_num(-100.0) }
336 } else {
337 sin_x / cos_x
338 }
339 }
340
341 #[inline]
342 fn to_radians(&self, degrees: fixed::types::I16F16) -> fixed::types::I16F16 {
343 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
344 degrees * pi / fixed::types::I16F16::from_num(180.0)
345 }
346
347 #[inline]
348 fn to_degrees(&self, radians: fixed::types::I16F16) -> fixed::types::I16F16 {
349 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
350 radians * fixed::types::I16F16::from_num(180.0) / pi
351 }
352
353 #[inline]
354 fn atan2(&self, y: fixed::types::I16F16, x: fixed::types::I16F16) -> fixed::types::I16F16 {
355 let zero = fixed::types::I16F16::ZERO;
357 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
358 let pi_2 = pi / 2;
359
360 if x == zero {
361 if y > zero {
362 return pi_2;
363 } else if y < zero {
364 return -pi_2;
365 } else {
366 return zero; }
368 }
369
370 let ratio = y / x;
372 let atan_ratio = self.atan_approx(ratio);
373
374 if x > zero {
375 atan_ratio
376 } else if y >= zero {
377 atan_ratio + pi
378 } else {
379 atan_ratio - pi
380 }
381 }
382}
383
384#[cfg(any(feature = "fixed-point", feature = "cordic-math"))]
385impl FixedPointBackend {
386 #[allow(clippy::only_used_in_recursion)]
388 fn atan_approx(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
389 let abs_x = x.abs();
390 let pi_4 = fixed::types::I16F16::from_num(core::f32::consts::FRAC_PI_4); if abs_x <= fixed::types::I16F16::ONE {
394 let x2 = x * x;
395 let x3 = x2 * x;
396 let x5 = x3 * x2;
397 let x7 = x5 * x2;
398
399 x - x3 / 3 + x5 / 5 - x7 / 7
400 } else {
401 let inv_x = fixed::types::I16F16::ONE / x;
403 let atan_inv = self.atan_approx(inv_x);
404
405 if x > fixed::types::I16F16::ZERO {
406 pi_4 * 2 - atan_inv
407 } else {
408 -pi_4 * 2 - atan_inv
409 }
410 }
411 }
412}
413
414#[cfg(feature = "integer-math")]
416pub struct IntegerBackend;
417
418#[cfg(feature = "integer-math")]
419impl MathBackend<i32> for IntegerBackend {
420 #[inline]
421 fn sqrt(&self, x: i32) -> i32 {
422 if x <= 0 {
423 return 0;
424 }
425
426 let mut left = 0i32;
428 let mut right = x;
429 let mut result = 0i32;
430
431 while left <= right {
432 let mid = left + (right - left) / 2;
433 let mid_squared = mid.saturating_mul(mid);
434
435 if mid_squared == x {
436 return mid;
437 } else if mid_squared < x {
438 left = mid + 1;
439 result = mid;
440 } else {
441 right = mid - 1;
442 }
443 }
444
445 result
446 }
447
448 #[inline]
449 fn abs(&self, x: i32) -> i32 {
450 x.abs()
451 }
452
453 #[inline]
454 fn min(&self, a: i32, b: i32) -> i32 {
455 if a < b {
456 a
457 } else {
458 b
459 }
460 }
461
462 #[inline]
463 fn max(&self, a: i32, b: i32) -> i32 {
464 if a > b {
465 a
466 } else {
467 b
468 }
469 }
470
471 #[inline]
472 fn floor(&self, x: i32) -> i32 {
473 x }
475
476 #[inline]
477 fn ceil(&self, x: i32) -> i32 {
478 x }
480
481 #[inline]
482 fn pow(&self, x: i32, y: i32) -> i32 {
483 if y == 0 {
484 return 1;
485 }
486 if y < 0 {
487 return 0; }
489
490 let mut result = 1i32;
491 let mut base = x;
492 let mut exp = y as u32;
493
494 while exp > 0 {
495 if exp & 1 == 1 {
496 result = result.saturating_mul(base);
497 }
498 base = base.saturating_mul(base);
499 exp >>= 1;
500 }
501 result
502 }
503
504 #[inline]
505 fn ln(&self, x: i32) -> i32 {
506 if x <= 0 {
508 return -1000; }
510
511 match x {
513 1 => 0,
514 2..=3 => 693, 4..=7 => 1386, 8..=15 => 2079, 16..=31 => 2772, _ => {
519 let bit_len = 32 - x.leading_zeros() as i32;
521 bit_len * 693 }
523 }
524 }
525
526 #[inline]
527 fn log10(&self, x: i32) -> i32 {
528 let ln_x = self.ln(x);
530 ln_x * 1000 / 2303 }
532
533 #[inline]
534 fn sin(&self, x: i32) -> i32 {
535 let pi_1000 = 3142; let two_pi_1000 = 6284; let mut angle = x % two_pi_1000;
542 if angle < 0 {
543 angle += two_pi_1000;
544 }
545
546 if angle <= pi_1000 / 2 {
548 (angle * 1000) / (pi_1000 / 2)
550 } else if angle <= pi_1000 {
551 ((pi_1000 - angle) * 1000) / (pi_1000 / 2)
553 } else if angle <= 3 * pi_1000 / 2 {
554 -((angle - pi_1000) * 1000) / (pi_1000 / 2)
556 } else {
557 -((two_pi_1000 - angle) * 1000) / (pi_1000 / 2)
559 }
560 }
561
562 #[inline]
563 fn cos(&self, x: i32) -> i32 {
564 let pi_2_1000 = 1571; self.sin(x + pi_2_1000)
567 }
568
569 #[inline]
570 fn tan(&self, x: i32) -> i32 {
571 let sin_x = self.sin(x);
572 let cos_x = self.cos(x);
573
574 if cos_x.abs() < 10 {
575 if sin_x >= 0 {
577 100000 } else {
579 -100000 }
581 } else {
582 (sin_x * 1000) / cos_x
583 }
584 }
585
586 #[inline]
587 fn to_radians(&self, degrees: i32) -> i32 {
588 (degrees * 3142) / (180 * 1000)
590 }
591
592 #[inline]
593 fn to_degrees(&self, radians: i32) -> i32 {
594 (radians * 180 * 1000) / 3142
596 }
597
598 #[inline]
599 fn atan2(&self, y: i32, x: i32) -> i32 {
600 let pi_1000 = 3142; let pi_2_1000 = 1571; if x == 0 {
606 if y > 0 {
607 return pi_2_1000;
608 } else if y < 0 {
609 return -pi_2_1000;
610 } else {
611 return 0; }
613 }
614
615 let abs_y = y.abs();
617 let abs_x = x.abs();
618
619 let angle = if abs_x >= abs_y {
621 (abs_y * pi_2_1000) / abs_x / 2 } else {
624 pi_2_1000 - (abs_x * pi_2_1000) / abs_y / 2
626 };
627
628 if x > 0 && y >= 0 {
630 angle } else if x <= 0 && y > 0 {
632 pi_1000 - angle } else if x < 0 && y <= 0 {
634 -pi_1000 + angle } else {
636 -angle }
638 }
639}
640
641#[cfg(feature = "cordic-math")]
643pub struct CordicBackend;
644
645#[cfg(feature = "cordic-math")]
646impl MathBackend<fixed::types::I16F16> for CordicBackend {
647 #[inline]
648 fn sqrt(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
649 let fixed_backend = FixedPointBackend;
651 fixed_backend.sqrt(x)
652 }
653
654 #[inline]
655 fn abs(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
656 x.abs()
657 }
658
659 #[inline]
660 fn min(&self, a: fixed::types::I16F16, b: fixed::types::I16F16) -> fixed::types::I16F16 {
661 if a < b {
662 a
663 } else {
664 b
665 }
666 }
667
668 #[inline]
669 fn max(&self, a: fixed::types::I16F16, b: fixed::types::I16F16) -> fixed::types::I16F16 {
670 if a > b {
671 a
672 } else {
673 b
674 }
675 }
676
677 #[inline]
678 fn floor(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
679 x.floor()
680 }
681
682 #[inline]
683 fn ceil(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
684 x.ceil()
685 }
686
687 #[inline]
688 fn pow(&self, x: fixed::types::I16F16, y: fixed::types::I16F16) -> fixed::types::I16F16 {
689 let fixed_backend = FixedPointBackend;
690 fixed_backend.pow(x, y)
691 }
692
693 #[inline]
694 fn ln(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
695 let fixed_backend = FixedPointBackend;
696 fixed_backend.ln(x)
697 }
698
699 #[inline]
700 fn log10(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
701 let fixed_backend = FixedPointBackend;
702 fixed_backend.log10(x)
703 }
704
705 #[inline]
706 fn sin(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
707 let (sin_val, _cos_val) = cordic::sin_cos(x);
709 sin_val
710 }
711
712 #[inline]
713 fn cos(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
714 let (_sin_val, cos_val) = cordic::sin_cos(x);
715 cos_val
716 }
717
718 #[inline]
719 fn tan(&self, x: fixed::types::I16F16) -> fixed::types::I16F16 {
720 let sin_x = self.sin(x);
721 let cos_x = self.cos(x);
722
723 if cos_x.abs() < fixed::types::I16F16::from_num(0.001) {
724 if sin_x >= fixed::types::I16F16::ZERO {
725 fixed::types::I16F16::from_num(100.0)
726 } else {
727 fixed::types::I16F16::from_num(-100.0)
728 }
729 } else {
730 sin_x / cos_x
731 }
732 }
733
734 #[inline]
735 fn to_radians(&self, degrees: fixed::types::I16F16) -> fixed::types::I16F16 {
736 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
737 degrees * pi / fixed::types::I16F16::from_num(180.0)
738 }
739
740 #[inline]
741 fn to_degrees(&self, radians: fixed::types::I16F16) -> fixed::types::I16F16 {
742 let pi = fixed::types::I16F16::from_num(core::f32::consts::PI);
743 radians * fixed::types::I16F16::from_num(180.0) / pi
744 }
745
746 #[inline]
747 fn atan2(&self, y: fixed::types::I16F16, x: fixed::types::I16F16) -> fixed::types::I16F16 {
748 let fixed_backend = FixedPointBackend;
750 fixed_backend.atan2(y, x)
751 }
752}
753
754#[cfg(feature = "floating-point")]
756pub use self::FloatingPointBackend as DefaultBackend;
757
758#[cfg(all(feature = "libm-math", not(feature = "floating-point")))]
759pub use self::LibmBackend as DefaultBackend;
760
761#[cfg(all(
762 feature = "fixed-point",
763 not(any(feature = "floating-point", feature = "libm-math"))
764))]
765pub use self::FixedPointBackend as DefaultBackend;
766
767#[cfg(all(
768 feature = "cordic-math",
769 not(any(
770 feature = "floating-point",
771 feature = "libm-math",
772 feature = "fixed-point"
773 ))
774))]
775pub use self::CordicBackend as DefaultBackend;
776
777#[cfg(all(
778 feature = "integer-math",
779 not(any(
780 feature = "floating-point",
781 feature = "libm-math",
782 feature = "fixed-point",
783 feature = "cordic-math"
784 ))
785))]
786pub use self::IntegerBackend as DefaultBackend;
787
788#[cfg(not(any(
790 feature = "floating-point",
791 feature = "libm-math",
792 feature = "fixed-point",
793 feature = "cordic-math",
794 feature = "integer-math"
795)))]
796pub struct FallbackBackend;
798
799#[cfg(not(any(
800 feature = "floating-point",
801 feature = "libm-math",
802 feature = "fixed-point",
803 feature = "cordic-math",
804 feature = "integer-math"
805)))]
806impl MathBackend<f32> for FallbackBackend {
807 fn sqrt(&self, x: f32) -> f32 {
808 if x <= 0.0 {
810 return 0.0;
811 }
812 let x_int = x as i32;
813 if x_int <= 0 {
814 return 0.0;
815 }
816
817 let mut left = 0i32;
819 let mut right = x_int;
820 let mut result = 0i32;
821
822 while left <= right {
823 let mid = left + (right - left) / 2;
824 let mid_squared = mid.saturating_mul(mid);
825
826 if mid_squared <= x_int {
827 result = mid;
828 left = mid + 1;
829 } else {
830 right = mid - 1;
831 }
832 }
833 result as f32
834 }
835 fn abs(&self, x: f32) -> f32 {
836 if x < 0.0 {
837 -x
838 } else {
839 x
840 }
841 }
842 fn min(&self, a: f32, b: f32) -> f32 {
843 if a < b {
844 a
845 } else {
846 b
847 }
848 }
849 fn max(&self, a: f32, b: f32) -> f32 {
850 if a > b {
851 a
852 } else {
853 b
854 }
855 }
856 fn floor(&self, x: f32) -> f32 {
857 (x as i32) as f32
858 }
859 fn ceil(&self, x: f32) -> f32 {
860 let int_part = x as i32;
861 if x > int_part as f32 {
862 (int_part + 1) as f32
863 } else {
864 int_part as f32
865 }
866 }
867 fn pow(&self, x: f32, y: f32) -> f32 {
868 if y == 0.0 {
870 return 1.0;
871 }
872 if y == 1.0 {
873 return x;
874 }
875 if y == 2.0 {
876 return x * x;
877 }
878 x
880 }
881 fn ln(&self, _x: f32) -> f32 {
882 0.0
883 } fn log10(&self, _x: f32) -> f32 {
885 0.0
886 } fn sin(&self, _x: f32) -> f32 {
888 0.0
889 } fn cos(&self, _x: f32) -> f32 {
891 1.0
892 } fn tan(&self, _x: f32) -> f32 {
894 0.0
895 } fn atan2(&self, _y: f32, _x: f32) -> f32 {
897 0.0
898 } fn to_radians(&self, degrees: f32) -> f32 {
900 degrees * 0.017453292
901 } fn to_degrees(&self, radians: f32) -> f32 {
903 radians * 57.29578
904 } }
906
907#[cfg(not(any(
908 feature = "floating-point",
909 feature = "libm-math",
910 feature = "fixed-point",
911 feature = "cordic-math",
912 feature = "integer-math"
913)))]
914pub use self::FallbackBackend as DefaultBackend;