embedded_charts/math/
mod.rs1pub mod backends;
13pub mod interpolation;
14pub mod traits;
15
16pub use traits::{FloatLike, MathOps, TrigOps};
18
19pub use backends::*;
21
22#[cfg(feature = "floating-point")]
24pub type Number = f32;
25
26#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
27pub type Number = fixed::types::I16F16;
29
30#[cfg(all(
31 feature = "integer-math",
32 not(any(feature = "floating-point", feature = "fixed-point"))
33))]
34pub type Number = i32;
36
37#[cfg(not(any(
38 feature = "floating-point",
39 feature = "fixed-point",
40 feature = "integer-math"
41)))]
42pub type Number = f32;
44
45pub struct Math;
47
48impl Math {
49 #[cfg(feature = "floating-point")]
51 pub fn backend() -> backends::FloatingPointBackend {
52 backends::FloatingPointBackend
53 }
54
55 #[cfg(all(feature = "libm-math", not(feature = "floating-point")))]
56 pub fn backend() -> backends::LibmBackend {
57 backends::LibmBackend
58 }
59
60 #[cfg(all(
61 feature = "fixed-point",
62 not(any(feature = "floating-point", feature = "libm-math"))
63 ))]
64 pub fn backend() -> backends::FixedPointBackend {
66 backends::FixedPointBackend
67 }
68
69 #[cfg(all(
70 feature = "cordic-math",
71 not(any(
72 feature = "floating-point",
73 feature = "libm-math",
74 feature = "fixed-point"
75 ))
76 ))]
77 pub fn backend() -> backends::CordicBackend {
78 backends::CordicBackend
79 }
80
81 #[cfg(all(
82 feature = "integer-math",
83 not(any(
84 feature = "floating-point",
85 feature = "libm-math",
86 feature = "fixed-point",
87 feature = "cordic-math"
88 ))
89 ))]
90 pub fn backend() -> backends::IntegerBackend {
92 backends::IntegerBackend
93 }
94
95 #[cfg(not(any(
96 feature = "floating-point",
97 feature = "libm-math",
98 feature = "fixed-point",
99 feature = "cordic-math",
100 feature = "integer-math"
101 )))]
102 pub fn backend() -> backends::FallbackBackend {
104 backends::FallbackBackend
105 }
106}
107
108impl Math {
110 #[inline]
112 pub fn sqrt(x: Number) -> Number {
113 use crate::math::traits::MathBackend;
114 Self::backend().sqrt(x)
115 }
116
117 #[inline]
119 pub fn abs(x: Number) -> Number {
120 use crate::math::traits::MathBackend;
121 Self::backend().abs(x)
122 }
123
124 #[inline]
126 pub fn min(a: Number, b: Number) -> Number {
127 use crate::math::traits::MathBackend;
128 Self::backend().min(a, b)
129 }
130
131 #[inline]
133 pub fn max(a: Number, b: Number) -> Number {
134 use crate::math::traits::MathBackend;
135 Self::backend().max(a, b)
136 }
137
138 #[inline]
140 pub fn floor(x: Number) -> Number {
141 use crate::math::traits::MathBackend;
142 Self::backend().floor(x)
143 }
144
145 #[inline]
147 pub fn ceil(x: Number) -> Number {
148 use crate::math::traits::MathBackend;
149 Self::backend().ceil(x)
150 }
151
152 #[inline]
154 pub fn pow(x: Number, y: Number) -> Number {
155 use crate::math::traits::MathBackend;
156 Self::backend().pow(x, y)
157 }
158
159 #[inline]
161 pub fn ln(x: Number) -> Number {
162 use crate::math::traits::MathBackend;
163 Self::backend().ln(x)
164 }
165
166 #[inline]
168 pub fn log10(x: Number) -> Number {
169 use crate::math::traits::MathBackend;
170 Self::backend().log10(x)
171 }
172
173 #[inline]
175 pub fn sin(x: Number) -> Number {
176 use crate::math::traits::MathBackend;
177 Self::backend().sin(x)
178 }
179
180 #[inline]
182 pub fn cos(x: Number) -> Number {
183 use crate::math::traits::MathBackend;
184 Self::backend().cos(x)
185 }
186
187 #[inline]
189 pub fn tan(x: Number) -> Number {
190 use crate::math::traits::MathBackend;
191 Self::backend().tan(x)
192 }
193
194 #[inline]
196 pub fn to_radians(degrees: Number) -> Number {
197 use crate::math::traits::MathBackend;
198 Self::backend().to_radians(degrees)
199 }
200
201 #[inline]
203 pub fn to_degrees(radians: Number) -> Number {
204 use crate::math::traits::MathBackend;
205 Self::backend().to_degrees(radians)
206 }
207
208 #[inline]
210 pub fn atan2(y: Number, x: Number) -> Number {
211 use crate::math::traits::MathBackend;
212 Self::backend().atan2(y, x)
213 }
214}
215
216pub trait NumericConversion<T> {
218 fn to_number(self) -> Number;
220 fn from_number(n: Number) -> T;
222}
223
224impl NumericConversion<f32> for f32 {
226 #[inline]
227 fn to_number(self) -> Number {
228 #[cfg(feature = "floating-point")]
229 return self;
230
231 #[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
232 return fixed::types::I16F16::from_num(self);
233
234 #[cfg(all(
235 feature = "integer-math",
236 not(any(feature = "floating-point", feature = "fixed-point"))
237 ))]
238 return (self * 1000.0) as i32; #[cfg(not(any(
241 feature = "floating-point",
242 feature = "fixed-point",
243 feature = "integer-math"
244 )))]
245 return self;
246 }
247
248 #[inline]
249 fn from_number(n: Number) -> f32 {
250 #[cfg(feature = "floating-point")]
251 return n;
252
253 #[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
254 return n.to_num();
255
256 #[cfg(all(
257 feature = "integer-math",
258 not(any(feature = "floating-point", feature = "fixed-point"))
259 ))]
260 return n as f32 / 1000.0; #[cfg(not(any(
263 feature = "floating-point",
264 feature = "fixed-point",
265 feature = "integer-math"
266 )))]
267 return n;
268 }
269}
270
271impl NumericConversion<i32> for i32 {
272 #[inline]
273 fn to_number(self) -> Number {
274 #[cfg(feature = "floating-point")]
275 return self as f32;
276
277 #[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
278 return fixed::types::I16F16::from_num(self);
279
280 #[cfg(all(
281 feature = "integer-math",
282 not(any(feature = "floating-point", feature = "fixed-point"))
283 ))]
284 return self * 1000; #[cfg(not(any(
287 feature = "floating-point",
288 feature = "fixed-point",
289 feature = "integer-math"
290 )))]
291 return self as f32;
292 }
293
294 #[inline]
295 fn from_number(n: Number) -> i32 {
296 #[cfg(feature = "floating-point")]
297 return n as i32;
298
299 #[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
300 return n.to_num();
301
302 #[cfg(all(
303 feature = "integer-math",
304 not(any(feature = "floating-point", feature = "fixed-point"))
305 ))]
306 return n / 1000; #[cfg(not(any(
309 feature = "floating-point",
310 feature = "fixed-point",
311 feature = "integer-math"
312 )))]
313 return n as i32;
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 #[cfg(not(feature = "integer-math"))] fn test_basic_math_operations() {
324 let a = 4.0f32.to_number();
325 let b = 2.0f32.to_number();
326
327 let sqrt_result = Math::sqrt(a);
328 let min_result = Math::min(a, b);
329 let max_result = Math::max(a, b);
330
331 assert!((f32::from_number(sqrt_result) - 2.0).abs() < 0.1);
333 assert!((f32::from_number(min_result) - 2.0).abs() < 0.1);
334 assert!((f32::from_number(max_result) - 4.0).abs() < 0.1);
335 }
336
337 #[test]
338 fn test_trigonometric_functions() {
339 let angle = 0.0f32.to_number();
340
341 let sin_result = Math::sin(angle);
342 let cos_result = Math::cos(angle);
343
344 assert!((f32::from_number(sin_result) - 0.0).abs() < 0.1);
346 assert!((f32::from_number(cos_result) - 1.0).abs() < 0.1);
347 }
348
349 #[test]
350 fn test_numeric_conversions() {
351 let original = core::f32::consts::PI;
352 let converted = original.to_number();
353 let back = f32::from_number(converted);
354
355 assert!((original - back).abs() < 0.1);
357 }
358}