1#![no_std]
35#![forbid(unsafe_code)]
36
37use core::f64::{self, consts::PI};
38
39const TAYLOR_SERIES_SUMS: usize = 16;
41const LN_SUM_TERMS: f64 = 101.0;
43
44pub const fn cos(mut x: f64) -> f64 {
54 while x < -0.1 {
56 x += 2.0 * PI;
57 }
58 while x > 2.0 * PI + 0.1 {
59 x -= 2.0 * PI;
60 }
61 let div = (x / PI) as u32;
62 x -= div as f64 * PI;
63 let sign = if div % 2 != 0 { -1.0 } else { 1.0 };
64
65 let mut result = 1.0;
66 let mut inter = 1.0;
67 let num = x * x;
68
69 let mut i = 1;
70 while i <= TAYLOR_SERIES_SUMS {
71 let comp = 2.0 * i as f64;
72 let den = comp * (comp - 1.0);
73 inter *= num / den;
74 if i % 2 == 0 {
75 result += inter;
76 } else {
77 result -= inter;
78 }
79 i += 1;
80 }
81
82 sign * result
83}
84
85pub const fn sin(x: f64) -> f64 {
95 cos(x - PI / 2.0)
96}
97
98pub const fn tan(x: f64) -> f64 {
108 sin(x) / cos(x)
109}
110
111pub const fn cot(x: f64) -> f64 {
121 let sin_calc = sin(x);
122 if sin_calc == 0.0 {
123 f64::INFINITY
124 } else {
125 cos(x) / sin_calc
126 }
127}
128
129pub const fn sec(x: f64) -> f64 {
139 let cos_calc = cos(x);
140 if cos_calc == 0.0 {
141 f64::INFINITY
142 } else {
143 1.0 / cos_calc
144 }
145}
146
147pub const fn csc(x: f64) -> f64 {
157 let sin_calc = sin(x);
158 if sin_calc == 0.0 {
159 f64::INFINITY
160 } else {
161 1.0 / sin_calc
162 }
163}
164
165pub const fn sinh(x: f64) -> f64 {
173 (exp(x) - exp(-x)) / 2.0
174}
175
176pub const fn cosh(x: f64) -> f64 {
184 (exp(x) + exp(-x)) / 2.0
185}
186
187pub const fn asin(x: f64) -> f64 {
195 if x.is_infinite() || x.abs() > 1.0 {
196 return f64::NAN;
197 } else if x == 1.0 {
198 return f64::consts::FRAC_PI_2;
199 } else if x == -1.0 {
200 return -f64::consts::FRAC_PI_2;
201 }
202
203 const RANGE_REDUCTION_THRESHOLD: f64 = 0.5;
207 if x.abs() > RANGE_REDUCTION_THRESHOLD {
208 let sign = x.signum();
209 let abs_x = x.abs();
210
211 let y = sqrt((1.0 - abs_x) / 2.0);
212 return sign * (f64::consts::FRAC_PI_2 - 2.0 * asin(y));
213 }
214
215 let mut n = 1;
216 let mut s = x;
217
218 while n < TAYLOR_SERIES_SUMS {
219 let numer1 = factorial(2.0 * n as f64);
220 let numer2 = expi(x, 2 * n + 1);
221
222 let denom1 = expi(4.0, n);
224 let denom2 = factorial(n as f64) * factorial(n as f64);
225 let denom3 = 2.0 * n as f64 + 1.0;
226
227 let f1 = numer1 / denom2;
229 let f2 = numer2 / denom1;
230
231 s += f1 * f2 / denom3;
232
233 n += 1;
234 }
235
236 s
237}
238
239pub const fn acos(x: f64) -> f64 {
248 if x.is_infinite() || x.abs() > 1.0 {
249 f64::NAN
250 } else {
251 f64::consts::FRAC_PI_2 - asin(x)
252 }
253}
254
255pub const fn asinh(x: f64) -> f64 {
263 if x.is_nan() {
264 f64::NAN
265 } else if x.is_infinite() {
266 x
267 } else {
268 ln(x + sqrt(x * x + 1.0))
269 }
270}
271
272pub const fn acosh(x: f64) -> f64 {
280 if x.is_nan() {
281 f64::NAN
282 } else if x.is_infinite() {
283 x
284 } else if x < 1.0 {
285 f64::NAN
286 } else {
287 ln(x + sqrt(x * x - 1.0))
288 }
289}
290
291const fn exp(x: f64) -> f64 {
293 let mut i = 1;
294 let mut s = 1.0;
295
296 while i < 16 {
297 s += expi(x, i) / factorial(i as f64);
298 i += 1;
299 }
300
301 s
302}
303
304const fn expi(x: f64, mut pow: usize) -> f64 {
306 let mut o = 1.0;
307
308 while pow > 0 {
309 o *= x;
310 pow -= 1;
311 }
312
313 o
314}
315
316const fn factorial(mut x: f64) -> f64 {
318 if x == 0.0 || x == 1.0 {
319 1.0
320 } else {
321 let mut s = 1.0;
322 while x > 1.0 {
323 s *= x;
324 x -= 1.0;
325 }
326 s
327 }
328}
329
330const fn sqrt(x: f64) -> f64 {
332 if x.is_nan() || x < 0.0 {
333 return f64::NAN;
334 } else if x.is_infinite() || x == 0.0 {
335 return x;
336 }
337
338 let mut current_guess = 1.0;
340
341 let mut i = 0;
342 while i < TAYLOR_SERIES_SUMS {
343 current_guess = 0.5 * (current_guess + x / current_guess);
344 i += 1;
345 }
346
347 current_guess
348}
349
350const fn ln(x: f64) -> f64 {
352 if x.is_nan() || x < 0.0 {
353 return f64::NAN;
354 } else if x == 0.0 {
355 return f64::NEG_INFINITY;
356 } else if x == 1.0 {
357 return 0.0;
358 } else if x.is_infinite() {
359 return f64::INFINITY;
360 }
361
362 let mut a = x;
365 let mut k = 0;
366
367 while a >= 2.0 {
369 a /= 2.0;
370 k += 1;
371 }
372 while a < 1.0 {
373 a *= 2.0;
374 k -= 1;
375 }
376
377 let x = a - 1.0;
378
379 let mut s = 0.0;
380 let mut term = x;
381 let mut n = 1.0;
382
383 while n < LN_SUM_TERMS {
384 s += term;
385 n += 1.0;
386 term = -term * x * (n - 1.0) / n;
387 }
388
389 s + (k as f64) * f64::consts::LN_2
390}
391
392#[cfg(test)]
393mod tests {
394 use core::f64::consts::{E, PI};
395
396 use crate::{cos, cosh, exp, expi, factorial, ln, sin, sinh, sqrt};
397
398 macro_rules! float_eq {
399 ($lhs:expr, $rhs:expr) => {
400 assert!(($lhs - $rhs).abs() < 0.0001, "lhs: {}, rhs: {}", $lhs, $rhs);
401 };
402 }
403
404 #[test]
405 fn test_factorial() {
406 assert_eq!(factorial(0.0), 1.0);
407 assert_eq!(factorial(1.0), 1.0);
408 assert_eq!(factorial(2.0), 2.0);
409 assert_eq!(factorial(3.0), 6.0);
410 assert_eq!(factorial(4.0), 24.0);
411 assert_eq!(factorial(5.0), 120.0);
412 }
413
414 #[test]
415 fn test_expi() {
416 assert_eq!(expi(2.0, 0), 1.0);
417 assert_eq!(expi(2.0, 4), 16.0);
418 assert_eq!(expi(2.0, 5), 32.0);
419 assert_eq!(expi(3.0, 3), 27.0);
420 }
421
422 #[test]
423 fn test_exp() {
424 float_eq!(exp(0.0), 1.0);
425 float_eq!(exp(1.0), E);
426 }
427
428 #[test]
429 fn test_sqrt() {
430 float_eq!(sqrt(0.0), 0.0);
431 float_eq!(sqrt(1.0), 1.0);
432 float_eq!(sqrt(4.0), 2.0);
433 float_eq!(sqrt(9.0), 3.0);
434 float_eq!(sqrt(16.0), 4.0);
435 float_eq!(sqrt(25.0), 5.0);
436 }
437
438 #[test]
439 fn test_cos() {
440 float_eq!(cos(0.0), 0.0_f64.cos());
441 float_eq!(cos(1.0), 1.0_f64.cos());
442 float_eq!(cos(PI), PI.cos());
443 float_eq!(cos(PI * 8.0), (PI * 8.0).cos());
444 }
445
446 #[test]
447 fn test_sin() {
448 float_eq!(sin(0.0), 0.0_f64.sin());
449 float_eq!(sin(1.0), 1.0_f64.sin());
450 float_eq!(sin(PI), PI.sin());
451 float_eq!(sin(PI * 8.0), (PI * 8.0).sin());
452 }
453
454 #[test]
455 fn test_sinh() {
456 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
457 float_eq!(sinh(x), x.sinh());
458 }
459 }
460
461 #[test]
462 fn test_cosh() {
463 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
464 float_eq!(cosh(x), x.cosh());
465 }
466 }
467
468 #[test]
469 fn test_ln() {
470 float_eq!(ln(0.01), 0.01_f64.ln());
471 float_eq!(ln(0.5), 0.5_f64.ln());
472 float_eq!(ln(1.0), 1.0_f64.ln());
473 float_eq!(ln(2.0), 2.0_f64.ln());
474 float_eq!(ln(10.0), 10.0_f64.ln());
475 float_eq!(ln(1_000.0), 1_000.0_f64.ln());
476 }
477}