Skip to main content

irox_tools/primitives/
f32.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5//!
6//! A collection of utilities for the f32 built-in
7//!
8
9use crate::{FloatIsh, FromF64, PrimitiveMath, ToF64, ToSigned};
10
11impl crate::f64::FloatExt for f32 {
12    type Type = f32;
13    type Size = u32;
14
15    fn trunc(self) -> f32 {
16        (self as u64) as f32
17    }
18
19    fn fract(self) -> f32 {
20        self - self.trunc()
21    }
22
23    fn abs(self) -> f32 {
24        f32::from_bits(self.to_bits() & 0x7FFF_FFFF)
25    }
26    fn round(self) -> f32 {
27        (self + 0.5 * self.signum()).trunc()
28    }
29
30    fn floor(self) -> f32 {
31        if self.is_sign_negative() {
32            return (self - 1.0).trunc();
33        }
34        self.trunc()
35    }
36
37    fn ceil(self) -> f32 {
38        if self.is_sign_positive() {
39            return (self + 1.0).trunc();
40        }
41        self.trunc()
42    }
43
44    fn signum(self) -> f32 {
45        if self.is_nan() {
46            return f32::NAN;
47        }
48        if self.is_sign_negative() {
49            return -1.0;
50        }
51        1.0
52    }
53
54    fn clamp(self, min: Self, max: Self) -> Self::Type {
55        if self < min {
56            return min;
57        } else if self > max {
58            return max;
59        }
60        self
61    }
62
63    ///
64    /// Implementation of Exponential Function from NIST DTMF eq 4.2.19: `<https://dlmf.nist.gov/4.2.E19>`
65    fn exp(self) -> Self::Type {
66        let mut out = 1.0;
67        let i = self;
68        let mut z = self;
69        let mut exp = 1.0;
70        let mut idx = 1;
71        let mut next = self;
72
73        while next.abs() > f32::EPSILON {
74            out += next;
75            idx += 1;
76            z *= i;
77            if z.is_infinite() {
78                break;
79            }
80            exp *= idx as Self::Type;
81            if exp.is_infinite() {
82                break;
83            }
84            next = z / exp;
85            if next.is_infinite() {
86                break;
87            }
88        }
89
90        out
91    }
92
93    ///
94    /// Implementation of Natural Logarithm using NIST DLMF eq 4.6.4: `<https://dlmf.nist.gov/4.6.E4>`
95    fn ln(self) -> Self::Type {
96        let z = self as f64;
97        let iter = (z - 1.) / (z + 1.);
98        let mut out = 0.0f64;
99        let mut next = iter;
100        let mut base = iter;
101        let mut idx = 1u64;
102        while next.abs() > f64::EPSILON {
103            out += next;
104            idx += 2;
105            base *= iter * iter;
106            next = base / idx as f64;
107        }
108        (out * 2.0) as f32
109    }
110
111    fn log10(self) -> Self::Type {
112        self.ln() / core::f32::consts::LN_10
113    }
114
115    /// Naive implementation of integer power fn.  Will do something smarter later.
116    fn powi(self, val: i32) -> Self::Type {
117        let mut out = self;
118        let i = self;
119        for _ in 0..val.abs() {
120            out *= i;
121        }
122        out
123    }
124
125    ///
126    /// Implementation of general power function using NIST DLMF eq 4.2.26: `<https://dlmf.nist.gov/4.2.E26>`
127    fn powf(self, a: Self::Type) -> Self::Type {
128        let z = self;
129
130        (a * z.ln()).exp()
131    }
132
133    fn sqrt(self) -> Self::Type {
134        self.powf(0.5)
135    }
136
137    fn to_bits(self) -> Self::Size {
138        f32::to_bits(self)
139    }
140
141    fn exponent(self) -> u16 {
142        ((self.to_bits() >> 23) & 0x0F) as u16
143    }
144
145    fn significand(self) -> Self::Size {
146        self.to_bits() & 0x7FFFFF
147    }
148
149    fn sin(self) -> Self::Type {
150        if cfg!(feature = "std") {
151            f32::sin(self)
152        } else {
153            todo!()
154        }
155    }
156
157    fn cos(self) -> Self::Type {
158        if cfg!(feature = "std") {
159            f32::cos(self)
160        } else {
161            todo!()
162        }
163    }
164    fn tan(self) -> Self::Type {
165        if cfg!(feature = "std") {
166            f32::tan(self)
167        } else {
168            self.sin() / self.cos()
169        }
170    }
171
172    fn atan(self) -> Self::Type {
173        if cfg!(feature = "std") {
174            f32::atan(self)
175        } else {
176            todo!()
177        }
178    }
179
180    fn atan2(self, o: Self) -> Self::Type {
181        if cfg!(feature = "std") {
182            f32::atan2(self, o)
183        } else {
184            let _o = o;
185            todo!()
186        }
187    }
188}
189
190impl ToF64 for f32 {
191    fn to_f64(&self) -> f64 {
192        *self as f64
193    }
194}
195impl FromF64 for f32 {
196    fn from_f64(value: f64) -> Self {
197        value as f32
198    }
199}
200
201impl ToSigned for f32 {
202    type Output = f32;
203
204    fn to_signed(self) -> Self::Output {
205        self
206    }
207
208    fn negative_one() -> Self::Output {
209        -1.
210    }
211}
212
213impl PrimitiveMath for f32 {}
214impl FloatIsh for f32 {}
215
216#[cfg(all(test, not(feature = "std")))]
217mod tests {
218    #[test]
219    pub fn test_ln() {
220        assert_eq!(0.0, crate::f64::FloatExt::ln(1.0_f32));
221        assert_eq_eps!(1.0, crate::f64::FloatExt::ln(core::f32::consts::E), 1e-6);
222        assert_eq_eps!(4.6051702, crate::f64::FloatExt::ln(100f32), 1e-6);
223        assert_eq_eps!(
224            11.09033963004403,
225            crate::f64::FloatExt::ln(u16::MAX as f32),
226            1e-6
227        );
228    }
229
230    #[test]
231    pub fn test_exp() {
232        assert_eq_eps!(1.0, crate::f64::FloatExt::exp(0.0f32), 1e-6);
233        assert_eq_eps!(
234            core::f32::consts::E,
235            crate::f64::FloatExt::exp(1.0f32),
236            1e-6
237        );
238        assert_eq_eps!(7.389056098930649, crate::f64::FloatExt::exp(2.0f32), 1e-6);
239        assert_eq_eps!(
240            15.154261,
241            crate::f64::FloatExt::exp(core::f32::consts::E),
242            1e-6
243        );
244    }
245}