fixed_math/traits/
trig.rs

1use crate::trig::*;
2use fixed::{
3    traits::FixedSigned,
4    types::extra::{LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8},
5    FixedI128, FixedI16, FixedI32, FixedI64, FixedI8,
6};
7
8use typenum::{IsLessOrEqual, Sum, True, U1, U12, U121, U124, U2, U25, U28, U4, U57, U60, U9};
9
10/// Calculation of sine, cosine and tangent for number in **degrees**.
11pub trait SinCos
12where
13    Self: Sized,
14{
15    /// Simultaneously calculate sine and cosine, returns `(sin(self), cos(self))`.
16    fn sin_cos(self) -> (Self, Self);
17    /// Calculate sine of an angle.
18    /// `sin_cos` should be used instead when both sine and cosine are needed.
19    fn sin(self) -> Self;
20    /// Calculate cosinus on an angle.
21    /// `sin_cos` should be used instead when both sine and cosine are needed.
22    fn cos(self) -> Self;
23    /// Calculate tangent of an angle if it exists.
24    fn tan(self) -> Option<Self>;
25}
26
27macro_rules! impl_sincos_deg {
28    ($f:ident, $leq:ident, $f0:ty) => {
29        impl<N> SinCos for $f<N>
30        where
31            N: $leq + IsLessOrEqual<$f0, Output = True>,
32            $f<N>: NormalizeCordic + CordicConstants,
33        {
34            fn sin_cos(self) -> (Self, Self) {
35                sin_cos(self)
36            }
37            fn sin(self) -> Self {
38                sin(self)
39            }
40            fn cos(self) -> Self {
41                cos(self)
42            }
43            fn tan(self) -> Option<Self> {
44                tan(self)
45            }
46        }
47    };
48}
49
50//TODO implement on sub-7 int bits too -> KN will need to be recalculated for each step down too...
51// Note: right now the atan table has 45 as highest entry which would overflow on 6 int bits.
52//       maybe skipping the highest entries in some way, the algorithm still works?
53impl_sincos_deg!(FixedI8, LeEqU8, U1);
54impl_sincos_deg!(FixedI16, LeEqU16, U9);
55impl_sincos_deg!(FixedI32, LeEqU32, U25);
56impl_sincos_deg!(FixedI64, LeEqU64, U57);
57impl_sincos_deg!(FixedI128, LeEqU128, U121);
58
59/// There are requirements for certain constants:
60///
61/// - FRAC_PI_2 needs 2 int bits
62/// - PI needs 3 int bits
63/// - TAU needs 4 int bits
64///
65/// => for a fixed number with N bits,
66///    we can have at most N - 3 fractional bits for constants to be representable
67pub trait FixedRadians: FixedSigned {
68    const FRAC_PI_2: Self;
69    const PI: Self;
70    const TAU: Self;
71}
72
73macro_rules! impl_rad_consts {
74    ($f:ident, $leq:ident, $f0:ty) => {
75        impl<N> FixedRadians for $f<N>
76        where
77            N: $leq + IsLessOrEqual<$f0, Output = True>,
78            N: $leq + IsLessOrEqual<Sum<$f0, U1>, Output = True>,
79            N: $leq + IsLessOrEqual<Sum<$f0, U2>, Output = True>,
80        {
81            const FRAC_PI_2: Self = $f::FRAC_PI_2;
82            const PI: Self = $f::PI;
83            const TAU: Self = $f::TAU;
84        }
85    };
86}
87
88impl_rad_consts!(FixedI8, LeEqU8, U4);
89impl_rad_consts!(FixedI16, LeEqU16, U12);
90impl_rad_consts!(FixedI32, LeEqU32, U28);
91impl_rad_consts!(FixedI64, LeEqU64, U60);
92impl_rad_consts!(FixedI128, LeEqU128, U124);
93
94impl SinCos for f32 {
95    fn sin_cos(self) -> (Self, Self) {
96        f32::sin_cos(self.to_radians())
97    }
98
99    fn sin(self) -> Self {
100        f32::sin(self.to_radians())
101    }
102
103    fn cos(self) -> Self {
104        f32::cos(self.to_radians())
105    }
106
107    fn tan(self) -> Option<Self> {
108        Some(f32::tan(self.to_radians()))
109    }
110}
111
112impl SinCos for f64 {
113    fn sin_cos(self) -> (Self, Self) {
114        f64::sin_cos(self.to_radians())
115    }
116
117    fn sin(self) -> Self {
118        f64::sin(self.to_radians())
119    }
120
121    fn cos(self) -> Self {
122        f64::cos(self.to_radians())
123    }
124
125    fn tan(self) -> Option<Self> {
126        Some(f64::tan(self.to_radians()))
127    }
128}