1#![no_std]
35#![forbid(unsafe_code)]
36
37use core::f64::{self, consts::PI};
38const TAYLOR_SERIES_SUMS: usize = 16;
39
40pub const fn cos(mut x: f64) -> f64 {
50 while x < -0.1 {
52 x += 2.0 * PI;
53 }
54 while x > 2.0 * PI + 0.1 {
55 x -= 2.0 * PI;
56 }
57 let div = (x / PI) as u32;
58 x -= div as f64 * PI;
59 let sign = if div % 2 != 0 { -1.0 } else { 1.0 };
60
61 let mut result = 1.0;
62 let mut inter = 1.0;
63 let num = x * x;
64
65 let mut i = 1;
66 while i <= TAYLOR_SERIES_SUMS {
67 let comp = 2.0 * i as f64;
68 let den = comp * (comp - 1.0);
69 inter *= num / den;
70 if i % 2 == 0 {
71 result += inter;
72 } else {
73 result -= inter;
74 }
75 i += 1;
76 }
77
78 sign * result
79}
80
81pub const fn sin(x: f64) -> f64 {
91 cos(x - PI / 2.0)
92}
93
94pub const fn tan(x: f64) -> f64 {
104 sin(x) / cos(x)
105}
106
107pub const fn cot(x: f64) -> f64 {
117 let sin_calc = sin(x);
118 if sin_calc == 0.0 {
119 f64::INFINITY
120 } else {
121 cos(x) / sin_calc
122 }
123}
124
125pub const fn sec(x: f64) -> f64 {
135 let cos_calc = cos(x);
136 if cos_calc == 0.0 {
137 f64::INFINITY
138 } else {
139 1.0 / cos_calc
140 }
141}
142
143pub const fn csc(x: f64) -> f64 {
153 let sin_calc = sin(x);
154 if sin_calc == 0.0 {
155 f64::INFINITY
156 } else {
157 1.0 / sin_calc
158 }
159}
160
161pub const fn sinh(x: f64) -> f64 {
169 (exp(x) - exp(-x)) / 2.0
170}
171
172pub const fn cosh(x: f64) -> f64 {
180 (exp(x) + exp(-x)) / 2.0
181}
182
183pub const fn asin(x: f64) -> f64 {
191 if x.is_infinite() {
192 return f64::NAN;
193 }
194 if x.abs() > 1.0 {
195 return f64::NAN;
196 }
197 if x == 1.0 {
198 return f64::consts::FRAC_PI_2;
199 }
200 if x == -1.0 {
201 return -f64::consts::FRAC_PI_2;
202 }
203
204 const RANGE_REDUCTION_THRESHOLD: f64 = 0.5;
208 if x.abs() > RANGE_REDUCTION_THRESHOLD {
209 let sign = x.signum();
210 let abs_x = x.abs();
211
212 let y = sqrt((1.0 - abs_x) / 2.0);
213 return sign * (f64::consts::FRAC_PI_2 - 2.0 * asin(y));
214 }
215
216 let mut n = 1;
217 let mut s = x;
218
219 while n < TAYLOR_SERIES_SUMS {
220 let numer1 = factorial(2.0 * n as f64);
221 let numer2 = expi(x, 2 * n + 1);
222
223 let denom1 = expi(4.0, n);
225 let denom2 = factorial(n as f64) * factorial(n as f64);
226 let denom3 = 2.0 * n as f64 + 1.0;
227
228 let f1 = numer1 / denom2;
230 let f2 = numer2 / denom1;
231
232 s += f1 * f2 / denom3;
233
234 n += 1;
235 }
236
237 s
238}
239
240pub const fn acos(x: f64) -> f64 {
249 if x.is_infinite() {
250 return f64::NAN;
251 }
252 if x.abs() > 1.0 {
253 return f64::NAN;
254 }
255
256 f64::consts::FRAC_PI_2 - asin(x)
257}
258
259const fn exp(x: f64) -> f64 {
261 let mut i = 1;
262 let mut s = 1.0;
263
264 while i < 16 {
265 s += expi(x, i) / factorial(i as f64);
266 i += 1;
267 }
268
269 s
270}
271
272const fn expi(x: f64, mut pow: usize) -> f64 {
274 let mut o = 1.0;
275
276 while pow > 0 {
277 o *= x;
278 pow -= 1;
279 }
280
281 o
282}
283
284const fn factorial(mut x: f64) -> f64 {
286 if x == 0.0 || x == 1.0 {
287 1.0
288 } else {
289 let mut s = 1.0;
290 while x > 1.0 {
291 s *= x;
292 x -= 1.0;
293 }
294 s
295 }
296}
297
298const fn sqrt(x: f64) -> f64 {
300 if x.is_nan() || x < 0.0 {
301 return f64::NAN;
302 }
303 if x.is_infinite() {
304 return x;
305 }
306 if x == 0.0 {
307 return x;
308 }
309
310 let mut current_guess = 1.0;
312
313 let mut i = 0;
314 while i < TAYLOR_SERIES_SUMS {
315 current_guess = 0.5 * (current_guess + x / current_guess);
316 i += 1;
317 }
318
319 current_guess
320}
321
322#[cfg(test)]
323mod tests {
324 use core::f64::consts::{E, PI};
325
326 use crate::{cos, cosh, exp, expi, factorial, sin, sinh, sqrt};
327
328 macro_rules! float_eq {
329 ($lhs:expr, $rhs:expr) => {
330 assert!(($lhs - $rhs).abs() < 0.0001, "lhs: {}, rhs: {}", $lhs, $rhs);
331 };
332 }
333
334 #[test]
335 fn test_factorial() {
336 assert_eq!(factorial(0.0), 1.0);
337 assert_eq!(factorial(1.0), 1.0);
338 assert_eq!(factorial(2.0), 2.0);
339 assert_eq!(factorial(3.0), 6.0);
340 assert_eq!(factorial(4.0), 24.0);
341 assert_eq!(factorial(5.0), 120.0);
342 }
343
344 #[test]
345 fn test_expi() {
346 assert_eq!(expi(2.0, 0), 1.0);
347 assert_eq!(expi(2.0, 4), 16.0);
348 assert_eq!(expi(2.0, 5), 32.0);
349 assert_eq!(expi(3.0, 3), 27.0);
350 }
351
352 #[test]
353 fn test_exp() {
354 float_eq!(exp(0.0), 1.0);
355 float_eq!(exp(1.0), E);
356 }
357
358 #[test]
359 fn test_sqrt() {
360 float_eq!(sqrt(4.0), 2.0);
361 float_eq!(sqrt(9.0), 3.0);
362 float_eq!(sqrt(16.0), 4.0);
363 float_eq!(sqrt(25.0), 5.0);
364 }
365
366 #[test]
367 fn test_cos() {
368 float_eq!(cos(0.0), 0.0_f64.cos());
369 float_eq!(cos(1.0), 1.0_f64.cos());
370 float_eq!(cos(PI), PI.cos());
371 float_eq!(cos(PI * 8.0), (PI * 8.0).cos());
372 }
373
374 #[test]
375 fn test_sin() {
376 float_eq!(sin(0.0), 0.0_f64.sin());
377 float_eq!(sin(1.0), 1.0_f64.sin());
378 float_eq!(sin(PI), PI.sin());
379 float_eq!(sin(PI * 8.0), (PI * 8.0).sin());
380 }
381
382 #[test]
383 fn test_sinh() {
384 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
385 float_eq!(sinh(x), x.sinh());
386 }
387 }
388
389 #[test]
390 fn test_cosh() {
391 for x in [0.0, 0.5, 1.0, 1.5, 2.0, 2.5] {
392 float_eq!(cosh(x), x.cosh());
393 }
394 }
395}