pub mod backends;
pub mod interpolation;
pub mod traits;
pub use traits::{FloatLike, MathOps, TrigOps};
pub use backends::*;
#[cfg(feature = "floating-point")]
pub type Number = f32;
#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
pub type Number = fixed::types::I16F16;
#[cfg(all(
feature = "integer-math",
not(any(feature = "floating-point", feature = "fixed-point"))
))]
pub type Number = i32;
#[cfg(not(any(
feature = "floating-point",
feature = "fixed-point",
feature = "integer-math"
)))]
pub type Number = f32;
pub struct Math;
impl Math {
#[cfg(feature = "floating-point")]
pub fn backend() -> backends::FloatingPointBackend {
backends::FloatingPointBackend
}
#[cfg(all(feature = "libm-math", not(feature = "floating-point")))]
pub fn backend() -> backends::LibmBackend {
backends::LibmBackend
}
#[cfg(all(
feature = "fixed-point",
not(any(feature = "floating-point", feature = "libm-math"))
))]
pub fn backend() -> backends::FixedPointBackend {
backends::FixedPointBackend
}
#[cfg(all(
feature = "cordic-math",
not(any(
feature = "floating-point",
feature = "libm-math",
feature = "fixed-point"
))
))]
pub fn backend() -> backends::CordicBackend {
backends::CordicBackend
}
#[cfg(all(
feature = "integer-math",
not(any(
feature = "floating-point",
feature = "libm-math",
feature = "fixed-point",
feature = "cordic-math"
))
))]
pub fn backend() -> backends::IntegerBackend {
backends::IntegerBackend
}
#[cfg(not(any(
feature = "floating-point",
feature = "libm-math",
feature = "fixed-point",
feature = "cordic-math",
feature = "integer-math"
)))]
pub fn backend() -> backends::FallbackBackend {
backends::FallbackBackend
}
}
impl Math {
#[inline]
pub fn sqrt(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().sqrt(x)
}
#[inline]
pub fn abs(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().abs(x)
}
#[inline]
pub fn min(a: Number, b: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().min(a, b)
}
#[inline]
pub fn max(a: Number, b: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().max(a, b)
}
#[inline]
pub fn floor(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().floor(x)
}
#[inline]
pub fn ceil(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().ceil(x)
}
#[inline]
pub fn pow(x: Number, y: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().pow(x, y)
}
#[inline]
pub fn ln(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().ln(x)
}
#[inline]
pub fn log10(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().log10(x)
}
#[inline]
pub fn sin(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().sin(x)
}
#[inline]
pub fn cos(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().cos(x)
}
#[inline]
pub fn tan(x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().tan(x)
}
#[inline]
pub fn to_radians(degrees: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().to_radians(degrees)
}
#[inline]
pub fn to_degrees(radians: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().to_degrees(radians)
}
#[inline]
pub fn atan2(y: Number, x: Number) -> Number {
use crate::math::traits::MathBackend;
Self::backend().atan2(y, x)
}
}
pub trait NumericConversion<T> {
fn to_number(self) -> Number;
fn from_number(n: Number) -> T;
}
impl NumericConversion<f32> for f32 {
#[inline]
fn to_number(self) -> Number {
#[cfg(feature = "floating-point")]
return self;
#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
return fixed::types::I16F16::from_num(self);
#[cfg(all(
feature = "integer-math",
not(any(feature = "floating-point", feature = "fixed-point"))
))]
return (self * 1000.0) as i32;
#[cfg(not(any(
feature = "floating-point",
feature = "fixed-point",
feature = "integer-math"
)))]
return self;
}
#[inline]
fn from_number(n: Number) -> f32 {
#[cfg(feature = "floating-point")]
return n;
#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
return n.to_num();
#[cfg(all(
feature = "integer-math",
not(any(feature = "floating-point", feature = "fixed-point"))
))]
return n as f32 / 1000.0;
#[cfg(not(any(
feature = "floating-point",
feature = "fixed-point",
feature = "integer-math"
)))]
return n;
}
}
impl NumericConversion<i32> for i32 {
#[inline]
fn to_number(self) -> Number {
#[cfg(feature = "floating-point")]
return self as f32;
#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
return fixed::types::I16F16::from_num(self);
#[cfg(all(
feature = "integer-math",
not(any(feature = "floating-point", feature = "fixed-point"))
))]
return self * 1000;
#[cfg(not(any(
feature = "floating-point",
feature = "fixed-point",
feature = "integer-math"
)))]
return self as f32;
}
#[inline]
fn from_number(n: Number) -> i32 {
#[cfg(feature = "floating-point")]
return n as i32;
#[cfg(all(feature = "fixed-point", not(feature = "floating-point")))]
return n.to_num();
#[cfg(all(
feature = "integer-math",
not(any(feature = "floating-point", feature = "fixed-point"))
))]
return n / 1000;
#[cfg(not(any(
feature = "floating-point",
feature = "fixed-point",
feature = "integer-math"
)))]
return n as i32;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(not(feature = "integer-math"))] fn test_basic_math_operations() {
let a = 4.0f32.to_number();
let b = 2.0f32.to_number();
let sqrt_result = Math::sqrt(a);
let min_result = Math::min(a, b);
let max_result = Math::max(a, b);
assert!((f32::from_number(sqrt_result) - 2.0).abs() < 0.1);
assert!((f32::from_number(min_result) - 2.0).abs() < 0.1);
assert!((f32::from_number(max_result) - 4.0).abs() < 0.1);
}
#[test]
fn test_trigonometric_functions() {
let angle = 0.0f32.to_number();
let sin_result = Math::sin(angle);
let cos_result = Math::cos(angle);
assert!((f32::from_number(sin_result) - 0.0).abs() < 0.1);
assert!((f32::from_number(cos_result) - 1.0).abs() < 0.1);
}
#[test]
fn test_numeric_conversions() {
let original = core::f32::consts::PI;
let converted = original.to_number();
let back = f32::from_number(converted);
assert!((original - back).abs() < 0.1);
}
}