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/// 
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/// 
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}