mixed_num/
trigonometry.rs

1pub mod atan;
2pub mod sqrt;
3
4/// Get the sign of the argument with a unit value.
5/// Zero is of positive sign.
6/// 
7/// ## Arguments
8/// 
9/// * `x`  - The function argument.
10/// 
11/// ## Example
12/// 
13/// ```
14/// use mixed_num::trigonometry::*;
15/// use fixed::{types::extra::U22, FixedI32};
16/// 
17/// let mut x = FixedI32::<U22>::from_num(-0.2);
18/// let mut y = sign(x);
19/// assert_eq!{ y.to_num::<f32>(), -1.0 };
20/// 
21/// x = FixedI32::<U22>::from_num(0.2);
22/// y = sign(x); 
23/// assert_eq!{ y.to_num::<f32>(), 1.0 };
24/// ``` 
25pub fn sign<T>( x:T ) -> T
26    where T: crate::MixedReal
27{
28    if x < T::mixed_from_num(0)
29    {
30        return T::mixed_from_num(-1);
31    }
32    else
33    {
34        return T::mixed_from_num(1);
35    }
36}
37
38/// Calculate sin(x) using a Taylor approximation of `sin(x)`.
39/// 
40/// Sin is calculated using the following polynomial:
41/// 
42/// `sin(x) = x -( x^3/6 )+( x^5/120 )-( x^7/5040 )+( x^9/362880 )`
43/// 
44/// ## Argument
45/// 
46/// * `x` - The value to apply the operation to.
47/// 
48/// `x` must be wrapped to the -π=<x<π range.
49/// 
50/// ## Example
51/// 
52/// ```
53/// use mixed_num::trigonometry::*;
54/// 
55/// let mut x:f32 = 0.0;
56/// let mut y = sin(x);
57/// assert_eq!{ y, 0.0 };
58/// 
59/// x = 3.1415/2.0;
60/// y = sin(x);
61/// assert_eq!{ y, 1.0000035 };
62/// 
63/// x = 3.1415;
64/// y = sin(x);
65/// assert_eq!{ y, 9.274483e-5 };
66/// ``` 
67/// 
68#[allow(dead_code)]
69pub fn sin<T>( x: T ) -> T
70    where T: crate::MixedNum + crate::MixedOps + crate::MixedPowi + crate::MixedNumSigned + crate::MixedPi
71{
72    let mixed_pi_half = T::mixed_pi()/T::mixed_from_num(2);
73
74    let mut x_ = x;
75
76    // Ensure that the angle is within the accurate range of the tailor series. 
77    if x < -mixed_pi_half
78    {   
79        let delta:T = x+mixed_pi_half;
80        x_ = -mixed_pi_half-delta;
81    }
82    else if mixed_pi_half < x
83    {
84        let delta:T = x-mixed_pi_half;
85        x_ = mixed_pi_half-delta;
86    }
87
88    // Calculate sine by using 
89    let mut sinx = x_-( x_.mixed_powi(3)/T::mixed_from_num(6) );
90    sinx += x_.mixed_powi(5)/T::mixed_from_num(120);
91    sinx -= x_.mixed_powi(7)/T::mixed_from_num(5040);
92    sinx += x_.mixed_powi(9)/T::mixed_from_num(362880);
93    return sinx;
94}
95
96/// Calculate cosine using a Taylor approximation of `cos(x)`.
97/// 
98/// Cos is calculated by adding a phase shift to x and running it through the polynomial sine method.
99/// 
100/// ## Argument
101/// 
102/// * `x` - The value to apply the operation to.
103/// 
104/// `x` is wrapped to the -π=<x<π range in the function.
105/// 
106/// ## Example
107/// 
108/// ```
109/// use mixed_num::trigonometry::*;
110/// 
111/// let mut x = 0f32;
112/// let mut y = cos(x);
113/// assert_eq!{ y, 1.0000035 };
114/// 
115/// x = 3.1415f32/2.0f32;
116/// y = cos(x);
117/// assert_eq!{ y, 4.6491623e-5 };
118/// ``` 
119/// 
120/// ## Comparison and Error
121/// 
122/// The figure below shows the comparison between the polynomial cosine, and the `std::f32::cos` implementation.
123/// The Difference between the two is plotted as the error.
124/// 
125/// ![Alt version](https://github.com/ErikBuer/Fixed-Trigonometry/blob/main/figures/polynomial_cosine_comparison.png?raw=true)
126/// 
127/// The error of the method is compared to the sine implementation in the cordic crate.
128/// 
129/// The comparison is done for U22 signed fixed point.
130/// 
131/// The figure below is missing numbers on the y axis, but it is plotted on a linear scale, showing the relative error between the two methods.
132/// 
133/// ![Alt version](https://github.com/ErikBuer/Fixed-Trigonometry/blob/main/figures/cordic_poly_cos_error_comparison.png?raw=true)
134/// 
135#[allow(dead_code)]
136pub fn cos<T>( x: T ) -> T
137    where T: crate::MixedNum + crate::MixedOps + crate::MixedPowi + crate::MixedWrapPhase + crate::MixedPi + crate::MixedNumSigned
138{
139    // shift to enable use of more accurate sinepolynomial method.
140    let mixed_pi_half = T::mixed_pi()/T::mixed_from_num(2);
141
142    let mut x_shifted = x+mixed_pi_half;
143    x_shifted = wrap_phase(x_shifted);
144    return sin(x_shifted);
145}
146
147/// Wrapps θ to the -π=<x<π range.
148/// 
149/// ## Arguments 
150///
151/// * `phi` - The unwrapped phase in radians.
152/// 
153/// ## Example
154/// 
155/// ```
156/// use mixed_num::trigonometry::*;
157/// use fixed::{types::extra::U28, FixedI32};
158/// 
159/// let phi =  FixedI32::<U28>::from_num(6);
160/// let wrapped_phi = wrap_phase(phi);
161/// assert_eq!{ wrapped_phi.to_num::<f32>(), -0.2831853 };
162/// ``` 
163pub fn wrap_phase<T>( phi: T ) -> T 
164    where T: crate::MixedNum + crate::MixedOps + crate::MixedPi + crate::MixedNumSigned
165{
166    let mixed_pi  = T::mixed_pi();
167    let tau = T::mixed_from_num(2)*mixed_pi;
168 
169    let mut temp_scalar = phi;
170    
171    while temp_scalar < -mixed_pi
172    {
173        temp_scalar = temp_scalar + tau;
174    }
175    while mixed_pi <= temp_scalar
176    {
177        temp_scalar = temp_scalar - tau;
178    }
179    return temp_scalar;
180}
181
182/// Rase fixed number to an integer-valued power.
183/// `base^power`.
184/// 
185/// ## Arguments
186/// 
187/// * `base`  - The base number.
188/// * `power` - The power to raise 'base' to.
189/// 
190/// ## Example
191/// 
192/// ```
193/// use mixed_num::trigonometry::*;
194/// use fixed::{types::extra::U22, FixedI32};
195/// 
196/// let mut x = FixedI32::<U22>::from_num(-2);
197/// let y = powi(x, 2);
198/// assert_eq!{ y.to_num::<f32>(), 4.0 };
199/// ``` 
200pub fn powi<T>( base:T, power:usize ) -> T
201    where T: crate::MixedNum + crate::MixedOps 
202{
203    if power==0
204    {
205        return T::mixed_from_num(1);
206    }
207
208    let mut temp:T = base;
209    for _i in 0..power-1 {
210        temp = temp*base;
211    }
212    return temp;
213}