#[inline(always)]
pub fn sinf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.sin() }
#[cfg(feature = "embedded")]
{ libm::sinf(x) }
}
#[inline(always)]
pub fn cosf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.cos() }
#[cfg(feature = "embedded")]
{ libm::cosf(x) }
}
#[inline(always)]
pub fn acosf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.acos() }
#[cfg(feature = "embedded")]
{ libm::acosf(x) }
}
#[inline(always)]
pub fn sinhf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.sinh() }
#[cfg(feature = "embedded")]
{ libm::sinhf(x) }
}
#[inline(always)]
pub fn sqrtf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.sqrt() }
#[cfg(feature = "embedded")]
{ libm::sqrtf(x) }
}
#[inline(always)]
pub fn logf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.ln() }
#[cfg(feature = "embedded")]
{ libm::logf(x) }
}
#[inline(always)]
pub fn expf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.exp() }
#[cfg(feature = "embedded")]
{ libm::expf(x) }
}
#[inline(always)]
pub fn log10f(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.log10() }
#[cfg(feature = "embedded")]
{ libm::log10f(x) }
}
#[inline(always)]
pub fn powf(base: f32, exp: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ base.powf(exp) }
#[cfg(feature = "embedded")]
{ libm::powf(base, exp) }
}
#[inline(always)]
pub fn roundf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.round() }
#[cfg(feature = "embedded")]
{ libm::roundf(x) }
}
#[inline(always)]
pub fn fabsf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.abs() }
#[cfg(feature = "embedded")]
{ libm::fabsf(x) }
}
#[inline(always)]
pub fn fmaxf(a: f32, b: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ a.max(b) }
#[cfg(feature = "embedded")]
{ libm::fmaxf(a, b) }
}
#[inline(always)]
pub fn fminf(a: f32, b: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ a.min(b) }
#[cfg(feature = "embedded")]
{ libm::fminf(a, b) }
}
#[inline(always)]
pub fn clampf(x: f32, lo: f32, hi: f32) -> f32 {
fmaxf(lo, fminf(x, hi))
}
#[inline(always)]
pub fn floorf(x: f32) -> f32 {
#[cfg(not(feature = "embedded"))]
{ x.floor() }
#[cfg(feature = "embedded")]
{ libm::floorf(x) }
}
#[inline(always)]
pub fn is_finite(x: f32) -> bool {
let bits = x.to_bits();
(bits & 0x7F80_0000) != 0x7F80_0000
}
pub fn sort_f32(slice: &mut [f32]) {
let n = slice.len();
for i in 1..n {
let key = slice[i];
let mut j = i;
while j > 0 && slice[j - 1] > key {
slice[j] = slice[j - 1];
j -= 1;
}
slice[j] = key;
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::f32::consts::PI;
const TOL: f32 = 1e-5;
#[test]
fn test_sinf() {
assert!(sinf(0.0).abs() < TOL);
assert!((sinf(PI / 2.0) - 1.0).abs() < TOL);
assert!((sinf(PI) - 0.0).abs() < TOL);
}
#[test]
fn test_cosf() {
assert!((cosf(0.0) - 1.0).abs() < TOL);
assert!(cosf(PI / 2.0).abs() < TOL);
assert!((cosf(PI) - (-1.0)).abs() < TOL);
}
#[test]
fn test_acosf() {
assert!(acosf(1.0).abs() < TOL);
assert!((acosf(0.0) - PI / 2.0).abs() < TOL);
assert!((acosf(-1.0) - PI).abs() < TOL);
}
#[test]
fn test_sinhf() {
assert!(sinhf(0.0).abs() < TOL);
assert!((sinhf(1.0) - 1.17520).abs() < 0.001);
}
#[test]
fn test_sqrtf() {
assert!((sqrtf(4.0) - 2.0).abs() < TOL);
assert!((sqrtf(9.0) - 3.0).abs() < TOL);
assert!(sqrtf(0.0).abs() < TOL);
}
#[test]
fn test_logf() {
assert!(logf(1.0).abs() < TOL);
assert!((logf(core::f32::consts::E) - 1.0).abs() < TOL);
}
#[test]
fn test_expf() {
assert!((expf(0.0) - 1.0).abs() < TOL);
assert!((expf(1.0) - core::f32::consts::E).abs() < 0.001);
}
#[test]
fn test_log10f() {
assert!(log10f(1.0).abs() < TOL);
assert!((log10f(10.0) - 1.0).abs() < TOL);
assert!((log10f(100.0) - 2.0).abs() < TOL);
}
#[test]
fn test_powf() {
assert!((powf(2.0, 3.0) - 8.0).abs() < TOL);
assert!((powf(10.0, 0.0) - 1.0).abs() < TOL);
assert!((powf(10.0, -1.0) - 0.1).abs() < 0.001);
}
#[test]
fn test_roundf() {
assert!((roundf(1.4) - 1.0).abs() < TOL);
assert!((roundf(1.5) - 2.0).abs() < TOL);
assert!((roundf(-0.6) - (-1.0)).abs() < TOL);
}
#[test]
fn test_fabsf() {
assert!((fabsf(-3.0) - 3.0).abs() < TOL);
assert!((fabsf(3.0) - 3.0).abs() < TOL);
assert!(fabsf(0.0) < TOL);
}
#[test]
fn test_fmaxf() {
assert!((fmaxf(1.0, 2.0) - 2.0).abs() < TOL);
assert!((fmaxf(-1.0, -2.0) - (-1.0)).abs() < TOL);
}
#[test]
fn test_fminf() {
assert!((fminf(1.0, 2.0) - 1.0).abs() < TOL);
assert!((fminf(-1.0, -2.0) - (-2.0)).abs() < TOL);
}
#[test]
fn test_clampf() {
assert!((clampf(0.5, 0.0, 1.0) - 0.5).abs() < TOL);
assert!((clampf(-1.0, 0.0, 1.0) - 0.0).abs() < TOL);
assert!((clampf(2.0, 0.0, 1.0) - 1.0).abs() < TOL);
}
#[test]
fn test_is_finite() {
assert!(is_finite(0.0));
assert!(is_finite(1.0));
assert!(is_finite(-1e30));
assert!(!is_finite(f32::INFINITY));
assert!(!is_finite(f32::NEG_INFINITY));
assert!(!is_finite(f32::NAN));
}
#[test]
fn test_sort_f32() {
let mut a = [3.0, 1.0, 4.0, 1.5, 2.0];
sort_f32(&mut a);
assert!((a[0] - 1.0).abs() < TOL);
assert!((a[1] - 1.5).abs() < TOL);
assert!((a[2] - 2.0).abs() < TOL);
assert!((a[3] - 3.0).abs() < TOL);
assert!((a[4] - 4.0).abs() < TOL);
sort_f32(&mut a);
assert!((a[0] - 1.0).abs() < TOL);
let mut b = [42.0];
sort_f32(&mut b);
assert!((b[0] - 42.0).abs() < TOL);
}
}