1#![no_std]
48#![forbid(unsafe_code)]
49
50use core::f64::{
51 self,
52 consts::{FRAC_PI_2, PI},
53};
54
55const TAYLOR_SERIES_SUMS: usize = 16;
57const LN_SUM_TERMS: f64 = 1001.0;
59const ATAN_SUMS: usize = 100_000;
62
63pub const fn cos(mut x: f64) -> f64 {
73 while x < -0.1 {
75 x += 2.0 * PI;
76 }
77 while x > 2.0 * PI + 0.1 {
78 x -= 2.0 * PI;
79 }
80 let div = (x / PI) as u32;
81 x -= div as f64 * PI;
82 let sign = if div % 2 != 0 { -1.0 } else { 1.0 };
83
84 let mut result = 1.0;
85 let mut inter = 1.0;
86 let num = x * x;
87
88 let mut i = 1;
89 while i <= TAYLOR_SERIES_SUMS {
90 let comp = 2.0 * i as f64;
91 let den = comp * (comp - 1.0);
92 inter *= num / den;
93 if i % 2 == 0 {
94 result += inter;
95 } else {
96 result -= inter;
97 }
98 i += 1;
99 }
100
101 sign * result
102}
103
104pub const fn sin(x: f64) -> f64 {
114 cos(x - PI / 2.0)
115}
116
117pub const fn tan(x: f64) -> f64 {
127 sin(x) / cos(x)
128}
129
130pub const fn cot(x: f64) -> f64 {
140 let sin_calc = sin(x);
141 if sin_calc == 0.0 {
142 f64::INFINITY
143 } else {
144 cos(x) / sin_calc
145 }
146}
147
148pub const fn sec(x: f64) -> f64 {
158 let cos_calc = cos(x);
159 if cos_calc == 0.0 {
160 f64::INFINITY
161 } else {
162 1.0 / cos_calc
163 }
164}
165
166pub const fn csc(x: f64) -> f64 {
176 let sin_calc = sin(x);
177 if sin_calc == 0.0 {
178 f64::INFINITY
179 } else {
180 1.0 / sin_calc
181 }
182}
183
184pub const fn sinh(x: f64) -> f64 {
192 (exp(x) - exp(-x)) / 2.0
193}
194
195pub const fn cosh(x: f64) -> f64 {
203 (exp(x) + exp(-x)) / 2.0
204}
205
206pub const fn asin(x: f64) -> f64 {
214 if x.is_infinite() || x.abs() > 1.0 {
215 return f64::NAN;
216 } else if x == 1.0 {
217 return f64::consts::FRAC_PI_2;
218 } else if x == -1.0 {
219 return -f64::consts::FRAC_PI_2;
220 }
221
222 const RANGE_REDUCTION_THRESHOLD: f64 = 0.5;
226 if x.abs() > RANGE_REDUCTION_THRESHOLD {
227 let sign = x.signum();
228 let abs_x = x.abs();
229
230 let y = sqrt((1.0 - abs_x) / 2.0);
231 return sign * (f64::consts::FRAC_PI_2 - 2.0 * asin(y));
232 }
233
234 let mut n = 1;
235 let mut s = x;
236
237 while n < TAYLOR_SERIES_SUMS {
238 let numer1 = factorial(2.0 * n as f64);
239 let numer2 = expi(x, 2 * n + 1);
240
241 let denom1 = expi(4.0, n);
243 let denom2 = factorial(n as f64) * factorial(n as f64);
244 let denom3 = 2.0 * n as f64 + 1.0;
245
246 let f1 = numer1 / denom2;
248 let f2 = numer2 / denom1;
249
250 s += f1 * f2 / denom3;
251
252 n += 1;
253 }
254
255 s
256}
257
258pub const fn acos(x: f64) -> f64 {
267 if x.is_infinite() || x.abs() > 1.0 {
268 f64::NAN
269 } else {
270 f64::consts::FRAC_PI_2 - asin(x)
271 }
272}
273
274pub const fn atan(x: f64) -> f64 {
284 if x.is_nan() {
285 return f64::NAN;
286 } else if x.is_infinite() {
287 if x > 0.0 {
288 return FRAC_PI_2;
289 } else {
290 return -FRAC_PI_2;
291 }
292 } else if x == 0.0 {
293 return 0.0;
294 }
295
296 const fn atan_taylor_series(x: f64) -> f64 {
297 let mut s = 0.0;
298 let mut term = x;
299 let mut sign = 1.0;
300 let x_squared = x * x;
301
302 let mut n = 0;
303 while n < ATAN_SUMS {
305 let denom = (2 * n + 1) as f64;
306 s += sign * term / denom;
307 term *= x_squared;
308 if sign == 1.0 {
309 sign = -1.0;
310 } else {
311 sign = 1.0;
312 }
313 n += 1;
314 }
315
316 s
317 }
318
319 if x > 1.0 {
320 FRAC_PI_2 - atan_taylor_series(1.0 / x)
321 } else if x < -1.0 {
322 -FRAC_PI_2 - atan_taylor_series(1.0 / x)
323 } else {
324 atan_taylor_series(x)
325 }
326}
327
328pub const fn atan2(y: f64, x: f64) -> f64 {
338 if x.is_nan() || y.is_nan() {
339 return f64::NAN;
340 }
341
342 if x == 0.0 {
343 if y > 0.0 {
344 FRAC_PI_2
345 } else if y < 0.0 {
346 -FRAC_PI_2
347 } else {
348 0.0
349 }
350 } else if x > 0.0 {
351 atan(y / x) } else if y >= 0.0 {
353 atan(y / x) + PI } else {
355 atan(y / x) - PI }
357}
358
359pub const fn asinh(x: f64) -> f64 {
367 if x.is_nan() {
368 f64::NAN
369 } else if x.is_infinite() {
370 x
371 } else {
372 ln(x + sqrt(x * x + 1.0))
373 }
374}
375
376pub const fn acosh(x: f64) -> f64 {
384 if x.is_nan() {
385 f64::NAN
386 } else if x.is_infinite() {
387 x
388 } else if x < 1.0 {
389 f64::NAN
390 } else {
391 ln(x + sqrt(x * x - 1.0))
392 }
393}
394
395const fn exp(x: f64) -> f64 {
397 let mut i = 1;
398 let mut s = 1.0;
399
400 while i < 16 {
401 s += expi(x, i) / factorial(i as f64);
402 i += 1;
403 }
404
405 s
406}
407
408const fn expi(x: f64, mut pow: usize) -> f64 {
410 let mut o = 1.0;
411
412 while pow > 0 {
413 o *= x;
414 pow -= 1;
415 }
416
417 o
418}
419
420const fn factorial(mut x: f64) -> f64 {
422 if x == 0.0 || x == 1.0 {
423 1.0
424 } else {
425 let mut s = 1.0;
426 while x > 1.0 {
427 s *= x;
428 x -= 1.0;
429 }
430 s
431 }
432}
433
434const fn sqrt(x: f64) -> f64 {
436 if x.is_nan() || x < 0.0 {
437 return f64::NAN;
438 } else if x.is_infinite() || x == 0.0 {
439 return x;
440 }
441
442 let mut current_guess = 1.0;
444
445 let mut i = 0;
446 while i < TAYLOR_SERIES_SUMS {
447 current_guess = 0.5 * (current_guess + x / current_guess);
448 i += 1;
449 }
450
451 current_guess
452}
453
454const fn ln(x: f64) -> f64 {
456 if x.is_nan() || x < 0.0 {
457 return f64::NAN;
458 } else if x == 0.0 {
459 return f64::NEG_INFINITY;
460 } else if x == 1.0 {
461 return 0.0;
462 } else if x.is_infinite() {
463 return f64::INFINITY;
464 }
465
466 let mut a = x;
469 let mut k = 0;
470
471 while a >= 2.0 {
473 a /= 2.0;
474 k += 1;
475 }
476 while a < 1.0 {
477 a *= 2.0;
478 k -= 1;
479 }
480
481 let x = a - 1.0;
482
483 let mut s = 0.0;
484 let mut term = x;
485 let mut n = 1.0;
486
487 while n < LN_SUM_TERMS {
488 s += term;
489 n += 1.0;
490 term = -term * x * (n - 1.0) / n;
491 }
492
493 s + (k as f64) * f64::consts::LN_2
494}
495
496#[cfg(test)]
497mod tests {
498 use core::f64::consts::{E, PI};
499
500 use crate::{cos, cosh, exp, expi, factorial, ln, sin, sinh, sqrt};
501
502 macro_rules! float_eq {
503 ($lhs:expr, $rhs:expr) => {
504 assert!(($lhs - $rhs).abs() < 0.0001, "lhs: {}, rhs: {}", $lhs, $rhs);
505 };
506 }
507
508 #[test]
509 fn test_factorial() {
510 assert_eq!(factorial(0.0), 1.0);
511 assert_eq!(factorial(1.0), 1.0);
512 assert_eq!(factorial(2.0), 2.0);
513 assert_eq!(factorial(3.0), 6.0);
514 assert_eq!(factorial(4.0), 24.0);
515 assert_eq!(factorial(5.0), 120.0);
516 }
517
518 #[test]
519 fn test_expi() {
520 assert_eq!(expi(2.0, 0), 1.0);
521 assert_eq!(expi(2.0, 4), 16.0);
522 assert_eq!(expi(2.0, 5), 32.0);
523 assert_eq!(expi(3.0, 3), 27.0);
524 }
525
526 #[test]
527 fn test_exp() {
528 float_eq!(exp(0.0), 1.0);
529 float_eq!(exp(1.0), E);
530 }
531
532 #[test]
533 fn test_sqrt() {
534 float_eq!(sqrt(0.0), 0.0);
535 float_eq!(sqrt(1.0), 1.0);
536 float_eq!(sqrt(4.0), 2.0);
537 float_eq!(sqrt(9.0), 3.0);
538 float_eq!(sqrt(16.0), 4.0);
539 float_eq!(sqrt(25.0), 5.0);
540 }
541
542 #[test]
543 fn test_cos() {
544 float_eq!(cos(0.0), 0.0_f64.cos());
545 float_eq!(cos(1.0), 1.0_f64.cos());
546 float_eq!(cos(PI), PI.cos());
547 float_eq!(cos(PI * 8.0), (PI * 8.0).cos());
548 }
549
550 #[test]
551 fn test_sin() {
552 float_eq!(sin(0.0), 0.0_f64.sin());
553 float_eq!(sin(1.0), 1.0_f64.sin());
554 float_eq!(sin(PI), PI.sin());
555 float_eq!(sin(PI * 8.0), (PI * 8.0).sin());
556 }
557
558 #[test]
559 fn test_sinh() {
560 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
561 float_eq!(sinh(x), x.sinh());
562 }
563 }
564
565 #[test]
566 fn test_cosh() {
567 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
568 float_eq!(cosh(x), x.cosh());
569 }
570 }
571
572 #[test]
573 fn test_ln() {
574 float_eq!(ln(0.01), 0.01_f64.ln());
575 float_eq!(ln(0.5), 0.5_f64.ln());
576 float_eq!(ln(1.0), 1.0_f64.ln());
577 float_eq!(ln(2.0), 2.0_f64.ln());
578 float_eq!(ln(10.0), 10.0_f64.ln());
579 float_eq!(ln(1_000.0), 1_000.0_f64.ln());
580 }
581}