1#[inline]
15pub fn sqrt_f32(x: f32) -> f32 {
16 if x <= 0.0 || x < 1e-10 {
17 return 0.0;
18 }
19 let mut g = x * 0.5;
20 for _ in 0..12 {
21 let next = 0.5 * (g + x / g);
22 if (next - g).abs() < g * 1.2e-7 {
23 return next;
24 }
25 g = next;
26 }
27 g
28}
29
30#[inline]
42pub fn exp_f32(x: f32) -> f32 {
43 if x >= 88.0 { return f32::MAX; }
45 if x <= -87.0 { return 0.0; }
46
47 const LN2: f32 = 0.693_147_18;
48 const LN2_INV: f32 = 1.442_695_04;
49
50 let n = floor_f32(x * LN2_INV + 0.5) as i32;
52 let r = x - n as f32 * LN2;
53
54 let p = 1.0 + r * (1.0 + r * (
57 0.5
58 + r * (1.666_666_7e-1
59 + r * (4.166_666_7e-2
60 + r * (8.333_333e-3
61 + r * 1.388_889e-3)))));
62
63 let pow2n = f32::from_bits(((n + 127) as u32).wrapping_shl(23));
66 p * pow2n
67}
68
69#[inline]
75pub fn floor_f32(x: f32) -> f32 {
76 let i = x as i32;
77 let fi = i as f32;
78 if x < fi { fi - 1.0 } else { fi }
81}
82
83#[inline]
87pub fn round_f32(x: f32) -> f32 {
88 if x >= 0.0 {
89 floor_f32(x + 0.5)
90 } else {
91 -floor_f32(-x + 0.5)
92 }
93}
94
95#[inline]
110pub fn ln_f32(x: f32) -> f32 {
111 if x <= 0.0 {
112 return f32::NEG_INFINITY;
113 }
114 let bits = x.to_bits();
116 let exp_biased = ((bits >> 23) & 0xFF) as i32;
117 let (e, m) = if exp_biased == 0 {
119 let leading = (bits << 9).leading_zeros() as i32;
121 let eff_exp = -126 - leading;
122 let m = f32::from_bits((bits << (leading as u32 + 1) & 0x007F_FFFF) | 0x3F80_0000);
124 (eff_exp, m)
125 } else {
126 let e = exp_biased - 127;
127 let m = f32::from_bits((bits & 0x007F_FFFF) | 0x3F80_0000);
128 (e, m)
129 };
130
131 let (m2, e2) = if m > 1.414_213_5_f32 {
133 (m * 0.5, e + 1)
134 } else {
135 (m, e)
136 };
137
138 let u = m2 - 1.0;
140
141 let p = u * (1.0
146 + u * (-0.5
147 + u * (0.333_333_3
148 + u * (-0.25
149 + u * (0.2
150 + u * (-0.166_666_7))))));
151
152 p + (e2 as f32) * core::f32::consts::LN_2
154}
155
156#[inline]
158pub fn mean_f32(xs: &[f32]) -> f32 {
159 if xs.is_empty() { return 0.0; }
160 xs.iter().sum::<f32>() / xs.len() as f32
161}
162
163#[inline]
165pub fn std_dev_f32(xs: &[f32]) -> f32 {
166 if xs.len() < 2 { return 0.0; }
167 let m = mean_f32(xs);
168 let var = xs.iter().map(|&x| (x - m) * (x - m)).sum::<f32>() / xs.len() as f32;
169 sqrt_f32(var)
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn sqrt_known_values() {
178 assert!((sqrt_f32(4.0) - 2.0).abs() < 1e-5, "sqrt(4)");
179 assert!((sqrt_f32(9.0) - 3.0).abs() < 1e-5, "sqrt(9)");
180 assert!((sqrt_f32(0.01) - 0.1).abs() < 1e-4, "sqrt(0.01)");
181 assert!((sqrt_f32(2.0) - 1.41421356).abs() < 1e-5, "sqrt(2)");
182 assert_eq!(sqrt_f32(0.0), 0.0, "sqrt(0)");
183 assert_eq!(sqrt_f32(-1.0), 0.0, "sqrt(-1)");
184 assert_eq!(sqrt_f32(1e-11), 0.0, "sub-epsilon returns 0");
185 }
186
187 #[test]
188 fn mean_basic() {
189 let xs = [1.0f32, 2.0, 3.0, 4.0, 5.0];
190 assert!((mean_f32(&xs) - 3.0).abs() < 1e-5);
191 }
192
193 #[test]
194 fn std_dev_zero_for_constant() {
195 let xs = [0.05f32; 50];
196 assert!(std_dev_f32(&xs) < 1e-4, "std_dev of constant must be ~0");
197 }
198
199 #[test]
200 fn std_dev_known() {
201 let xs = [0.0f32, 1.0, 2.0, 3.0, 4.0];
202 let s = std_dev_f32(&xs);
203 assert!((s - 1.41421).abs() < 1e-3, "std_dev={}", s);
204 }
205
206 #[test]
208 fn exp_zero_is_one() {
209 assert!((exp_f32(0.0) - 1.0).abs() < 1e-6, "e^0 = 1");
210 }
211
212 #[test]
213 fn exp_one() {
214 assert!((exp_f32(1.0) - 2.718_282).abs() < 1e-4, "e^1");
216 }
217
218 #[test]
219 fn exp_minus_one() {
220 assert!((exp_f32(-1.0) - 0.367_879).abs() < 1e-4, "e^-1");
221 }
222
223 #[test]
224 fn exp_ln2_is_two() {
225 assert!((exp_f32(0.693_147) - 2.0).abs() < 1e-4, "e^ln2 = 2");
227 }
228
229 #[test]
230 fn exp_negative_large() {
231 assert!((exp_f32(-5.0) - 0.006_738).abs() < 1e-4, "e^-5");
233 }
234
235 #[test]
236 fn exp_positive_large() {
237 assert!((exp_f32(10.0) - 22026.47).abs() < 10.0, "e^10");
239 }
240
241 #[test]
242 fn exp_clamp_overflow() {
243 assert_eq!(exp_f32(100.0), f32::MAX, "overflow clamp");
244 }
245
246 #[test]
247 fn exp_clamp_underflow() {
248 assert_eq!(exp_f32(-100.0), 0.0, "underflow clamp");
249 }
250
251 #[test]
253 fn ln_one_is_zero() {
254 assert!((ln_f32(1.0)).abs() < 1e-6, "ln(1) = 0");
255 }
256
257 #[test]
258 fn ln_e_is_one() {
259 use core::f32::consts::E;
260 assert!((ln_f32(E) - 1.0).abs() < 1e-4, "ln(e) ≈ 1");
261 }
262
263 #[test]
264 fn ln_two() {
265 assert!((ln_f32(2.0) - 0.693_147).abs() < 1e-4, "ln(2)");
267 }
268
269 #[test]
270 fn ln_inverse_of_exp() {
271 for i in -5_i32..=5 {
273 let x = i as f32;
274 let roundtrip = ln_f32(exp_f32(x));
275 assert!((roundtrip - x).abs() < 1e-3,
276 "ln(exp({})) = {} (expected {})", x, roundtrip, x);
277 }
278 }
279
280 #[test]
281 fn ln_negative_is_neg_infinity() {
282 assert_eq!(ln_f32(-1.0), f32::NEG_INFINITY);
283 assert_eq!(ln_f32(0.0), f32::NEG_INFINITY);
284 }
285
286 #[test]
287 fn ln_large_value() {
288 assert!((ln_f32(1000.0) - 6.907_755).abs() < 0.01, "ln(1000)");
290 }
291}