1#[cfg(feature = "f32")]
15use libm::{
16 acosf as libm_acos, asinf as libm_asin, atan2f as libm_atan2, atanf as libm_atan,
17 ceilf as libm_ceil, cosf as libm_cos, coshf as libm_cosh, expf as libm_exp,
18 floorf as libm_floor, log10f as libm_log10, logf as libm_ln, powf as libm_pow,
19 sinf as libm_sin, sinhf as libm_sinh, sqrtf as libm_sqrt, tanf as libm_tan, tanhf as libm_tanh,
20};
21
22#[cfg(not(feature = "f32"))]
23use libm::{
24 acos as libm_acos, asin as libm_asin, atan as libm_atan, atan2 as libm_atan2,
25 ceil as libm_ceil, cos as libm_cos, cosh as libm_cosh, exp as libm_exp, floor as libm_floor,
26 log as libm_ln, log10 as libm_log10, pow as libm_pow, sin as libm_sin, sinh as libm_sinh,
27 sqrt as libm_sqrt, tan as libm_tan, tanh as libm_tanh,
28};
29
30use crate::Real;
31
32pub fn dummy(_: Real, _: Real) -> Real {
37 panic!("called dummy!")
38}
39
40pub fn max(a: Real, b: Real) -> Real {
51 if a > b {
52 a
53 } else {
54 b
55 }
56}
57
58pub fn add(a: Real, b: Real) -> Real {
69 a + b
70}
71
72pub fn min(a: Real, b: Real) -> Real {
83 if a < b {
84 a
85 } else {
86 b
87 }
88}
89
90pub fn sub(a: Real, b: Real) -> Real {
101 a - b
102}
103
104pub fn mul(a: Real, b: Real) -> Real {
115 a * b
116}
117
118pub fn div(a: Real, b: Real) -> Real {
134 if b == 0.0 {
135 if a == 0.0 {
136 #[cfg(feature = "f32")]
137 return f32::NAN; #[cfg(not(feature = "f32"))]
139 return f64::NAN; } else if a > 0.0 {
141 #[cfg(feature = "f32")]
142 return f32::INFINITY; #[cfg(not(feature = "f32"))]
144 return f64::INFINITY; } else {
146 #[cfg(feature = "f32")]
147 return f32::NEG_INFINITY; #[cfg(not(feature = "f32"))]
149 return f64::NEG_INFINITY; }
151 } else {
152 a / b
153 }
154}
155pub fn fmod(a: Real, b: Real) -> Real {
156 a % b
157}
158pub fn neg(a: Real, _: Real) -> Real {
159 -a
160}
161pub fn comma(_: Real, b: Real) -> Real {
162 b
163}
164pub fn abs(a: Real, _: Real) -> Real {
165 a.abs()
166}
167pub fn acos(a: Real, _: Real) -> Real {
168 if !(-1.0..=1.0).contains(&a) {
169 #[cfg(feature = "f32")]
170 return f32::NAN; #[cfg(not(feature = "f32"))]
172 return f64::NAN; } else {
174 libm_acos(a)
175 }
176}
177pub fn asin(a: Real, _: Real) -> Real {
178 if !(-1.0..=1.0).contains(&a) {
179 #[cfg(feature = "f32")]
180 return f32::NAN; #[cfg(not(feature = "f32"))]
182 return f64::NAN; } else {
184 libm_asin(a)
185 }
186}
187pub fn atan(a: Real, _: Real) -> Real {
188 libm_atan(a)
189}
190pub fn atan2(a: Real, b: Real) -> Real {
191 #[cfg(test)]
197 println!("atan2 called with a={}, b={}", a, b);
198
199 let result = libm_atan2(a, b); #[cfg(test)]
202 println!("atan2 result: {}", result);
203
204 result
205}
206pub fn ceil(a: Real, _: Real) -> Real {
207 libm_ceil(a)
208}
209pub fn cos(a: Real, _: Real) -> Real {
210 libm_cos(a)
211}
212pub fn cosh(a: Real, _: Real) -> Real {
213 libm_cosh(a)
214}
215pub fn e(_: Real, _: Real) -> Real {
216 crate::constants::E
217}
218pub fn exp(a: Real, _: Real) -> Real {
219 libm_exp(a)
220}
221pub fn floor(a: Real, _: Real) -> Real {
222 libm_floor(a)
223}
224pub fn ln(a: Real, _: Real) -> Real {
225 if a <= 0.0 {
226 #[cfg(feature = "f32")]
227 return f32::NAN; #[cfg(not(feature = "f32"))]
229 return f64::NAN; } else {
231 libm_ln(a)
232 }
233}
234pub fn log(a: Real, _: Real) -> Real {
235 if a <= 0.0 {
236 #[cfg(feature = "f32")]
237 return f32::NAN; #[cfg(not(feature = "f32"))]
239 return f64::NAN; } else {
241 libm_log10(a)
242 }
243}
244pub fn log10(a: Real, _: Real) -> Real {
245 if a <= 0.0 {
246 #[cfg(feature = "f32")]
247 return f32::NAN; #[cfg(not(feature = "f32"))]
249 return f64::NAN; } else {
251 libm_log10(a)
252 }
253}
254pub fn pi(_: Real, _: Real) -> Real {
255 crate::constants::PI
256}
257pub fn pow(a: Real, b: Real) -> Real {
276 #[cfg(test)]
277 println!("pow function called with a={}, b={}", a, b);
278
279 if a == 0.0 && b == 0.0 {
281 return 1.0; }
283
284 if a < 0.0 && b != libm_floor(b) {
285 #[cfg(feature = "f32")]
287 return f32::NAN;
288 #[cfg(not(feature = "f32"))]
289 return f64::NAN;
290 }
291
292 #[cfg(feature = "f32")]
294 if a.abs() > 1.0 && b > 88.0 {
295 return if a > 0.0 {
296 f32::INFINITY
297 } else {
298 f32::NEG_INFINITY
299 };
300 }
301
302 #[cfg(not(feature = "f32"))]
303 if a.abs() > 1.0 && b > 709.0 {
304 return if a > 0.0 {
305 f64::INFINITY
306 } else {
307 f64::NEG_INFINITY
308 };
309 }
310
311 #[cfg(feature = "f32")]
312 if a.abs() < 1.0 && b < -88.0 {
313 return 0.0; }
315
316 #[cfg(not(feature = "f32"))]
317 if a.abs() < 1.0 && b < -709.0 {
318 return 0.0; }
320
321 libm_pow(a, b)
322}
323pub fn sin(a: Real, _: Real) -> Real {
324 libm_sin(a)
325}
326pub fn sinh(a: Real, _: Real) -> Real {
327 libm_sinh(a)
328}
329pub fn sqrt(a: Real, _: Real) -> Real {
330 if a < 0.0 {
331 #[cfg(feature = "f32")]
332 return f32::NAN; #[cfg(not(feature = "f32"))]
334 return f64::NAN; } else {
336 libm_sqrt(a)
337 }
338}
339pub fn tan(a: Real, _: Real) -> Real {
340 libm_tan(a)
341}
342pub fn tanh(a: Real, _: Real) -> Real {
343 libm_tanh(a)
344}
345
346pub fn sign(a: Real, _: Real) -> Real {
347 if a > 0.0 {
348 1.0
349 } else if a < 0.0 {
350 -1.0
351 } else {
352 0.0
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359
360 #[test]
361 #[should_panic(expected = "called dummy!")]
362 fn test_dummy_panics() {
363 dummy(1.0, 2.0);
364 }
365
366 #[test]
367 fn test_sub() {
368 assert_eq!(sub(5.0, 3.0), 2.0);
369 }
370
371 #[test]
372 fn test_mul() {
373 assert_eq!(mul(2.0, 3.0), 6.0);
374 }
375
376 #[test]
377 fn test_div() {
378 assert_eq!(div(6.0, 3.0), 2.0);
379 }
380
381 #[test]
382 fn test_fmod() {
383 assert_eq!(fmod(7.0, 4.0), 3.0);
384 }
385
386 #[test]
387 fn test_neg() {
388 assert_eq!(neg(5.0, 0.0), -5.0);
389 }
390
391 #[test]
392 fn test_comma() {
393 assert_eq!(comma(1.0, 2.0), 2.0);
394 }
395
396 #[test]
397 fn test_abs() {
398 assert_eq!(abs(-5.0, 0.0), 5.0);
399 }
400
401 #[test]
402 fn test_acos() {
403 assert!((acos(1.0, 0.0) - 0.0).abs() < 1e-10);
404 }
405
406 #[test]
407 fn test_asin() {
408 assert!((asin(0.0, 0.0) - 0.0).abs() < 1e-10);
409 }
410
411 #[test]
412 fn test_atan() {
413 assert!((atan(0.0, 0.0) - 0.0).abs() < 1e-10);
414 }
415
416 #[test]
417 fn test_atan2() {
418 #[cfg(feature = "f32")]
420 assert!((atan2(1.0, 1.0) - core::f32::consts::FRAC_PI_4).abs() < 1e-6);
421 #[cfg(not(feature = "f32"))]
422 assert!((atan2(1.0, 1.0) - core::f64::consts::FRAC_PI_4).abs() < 1e-10);
423
424 assert!(
429 (atan2(1.0, 2.0) - 0.4636476090008061).abs() < 1e-10,
430 "atan2(1.0, 2.0) should be approximately 0.4636"
431 );
432
433 #[cfg(feature = "f32")]
435 assert!(
436 (atan2(1.0, -1.0) - (3.0 * core::f32::consts::FRAC_PI_4)).abs() < 1e-6,
437 "atan2(1.0, -1.0) should be approximately 3π/4"
438 );
439 #[cfg(not(feature = "f32"))]
440 assert!(
441 (atan2(1.0, -1.0) - (3.0 * core::f64::consts::FRAC_PI_4)).abs() < 1e-10,
442 "atan2(1.0, -1.0) should be approximately 3π/4"
443 );
444
445 #[cfg(feature = "f32")]
447 assert!(
448 (atan2(-1.0, -1.0) + (3.0 * core::f32::consts::FRAC_PI_4)).abs() < 1e-6,
449 "atan2(-1.0, -1.0) should be approximately -3π/4"
450 );
451 #[cfg(not(feature = "f32"))]
452 assert!(
453 (atan2(-1.0, -1.0) + (3.0 * core::f64::consts::FRAC_PI_4)).abs() < 1e-10,
454 "atan2(-1.0, -1.0) should be approximately -3π/4"
455 );
456
457 #[cfg(feature = "f32")]
459 assert!(
460 (atan2(-1.0, 1.0) + core::f32::consts::FRAC_PI_4).abs() < 1e-6,
461 "atan2(-1.0, 1.0) should be approximately -π/4"
462 );
463 #[cfg(not(feature = "f32"))]
464 assert!(
465 (atan2(-1.0, 1.0) + core::f64::consts::FRAC_PI_4).abs() < 1e-10,
466 "atan2(-1.0, 1.0) should be approximately -π/4"
467 );
468
469 assert!(
471 (atan2(0.0, 1.0) - 0.0).abs() < 1e-10,
472 "atan2(0.0, 1.0) should be 0"
473 );
474
475 #[cfg(feature = "f32")]
476 assert!(
477 (atan2(1.0, 0.0) - core::f32::consts::FRAC_PI_2).abs() < 1e-6,
478 "atan2(1.0, 0.0) should be π/2"
479 );
480 #[cfg(not(feature = "f32"))]
481 assert!(
482 (atan2(1.0, 0.0) - core::f64::consts::FRAC_PI_2).abs() < 1e-10,
483 "atan2(1.0, 0.0) should be π/2"
484 );
485
486 #[cfg(feature = "f32")]
487 assert!(
488 (atan2(0.0, -1.0) - core::f32::consts::PI).abs() < 1e-6,
489 "atan2(0.0, -1.0) should be π"
490 );
491 #[cfg(not(feature = "f32"))]
492 assert!(
493 (atan2(0.0, -1.0) - core::f64::consts::PI).abs() < 1e-10,
494 "atan2(0.0, -1.0) should be π"
495 );
496
497 #[cfg(feature = "f32")]
498 assert!(
499 (atan2(-1.0, 0.0) + core::f32::consts::FRAC_PI_2).abs() < 1e-6,
500 "atan2(-1.0, 0.0) should be -π/2"
501 );
502 #[cfg(not(feature = "f32"))]
503 assert!(
504 (atan2(-1.0, 0.0) + core::f64::consts::FRAC_PI_2).abs() < 1e-10,
505 "atan2(-1.0, 0.0) should be -π/2"
506 );
507
508 println!("atan2(1.0, 2.0) = {}", atan2(1.0, 2.0));
510 println!("atan2(2.0, 1.0) = {}", atan2(2.0, 1.0));
511 }
512
513 #[test]
514 fn test_ceil() {
515 assert_eq!(ceil(2.3, 0.0), 3.0);
516 }
517
518 #[test]
519 fn test_cos() {
520 assert!((cos(0.0, 0.0) - 1.0).abs() < 1e-10);
521 }
522
523 #[test]
524 fn test_cosh() {
525 assert!((cosh(0.0, 0.0) - 1.0).abs() < 1e-10);
526 }
527
528 #[test]
529 fn test_e() {
530 #[cfg(feature = "f32")]
531 assert!((e(0.0, 0.0) - core::f32::consts::E).abs() < 1e-6);
532 #[cfg(not(feature = "f32"))]
533 assert!((e(0.0, 0.0) - core::f64::consts::E).abs() < 1e-10);
534 }
535
536 #[test]
537 fn test_exp() {
538 #[cfg(feature = "f32")]
539 assert!((exp(1.0, 0.0) - core::f32::consts::E).abs() < 1e-6);
540 #[cfg(not(feature = "f32"))]
541 assert!((exp(1.0, 0.0) - core::f64::consts::E).abs() < 1e-10);
542 }
543
544 #[test]
545 fn test_floor() {
546 assert_eq!(floor(2.7, 0.0), 2.0);
547 }
548
549 #[test]
550 fn test_ln() {
551 #[cfg(feature = "f32")]
552 assert!((ln(core::f32::consts::E, 0.0) - 1.0).abs() < 1e-6);
553 #[cfg(not(feature = "f32"))]
554 assert!((ln(core::f64::consts::E, 0.0) - 1.0).abs() < 1e-10);
555 }
556
557 #[test]
558 fn test_log() {
559 assert!((log(1000.0, 0.0) - 3.0).abs() < 1e-10);
560 }
561
562 #[test]
563 fn test_log10() {
564 assert!((log10(1000.0, 0.0) - 3.0).abs() < 1e-10);
565 }
566
567 #[test]
568 fn test_pi() {
569 #[cfg(feature = "f32")]
570 assert!((pi(0.0, 0.0) - core::f32::consts::PI).abs() < 1e-6);
571 #[cfg(not(feature = "f32"))]
572 assert!((pi(0.0, 0.0) - core::f64::consts::PI).abs() < 1e-10);
573 }
574
575 #[test]
576 fn test_pow() {
577 assert_eq!(pow(2.0, 3.0), 8.0);
578 }
579
580 #[test]
581 fn test_sin() {
582 assert!((sin(0.0, 0.0) - 0.0).abs() < 1e-10);
583 }
584
585 #[test]
586 fn test_sinh() {
587 assert!((sinh(0.0, 0.0) - 0.0).abs() < 1e-10);
588 }
589
590 #[test]
591 fn test_sqrt() {
592 assert_eq!(sqrt(4.0, 0.0), 2.0);
593 }
594
595 #[test]
596 fn test_tan() {
597 assert!((tan(0.0, 0.0) - 0.0).abs() < 1e-10);
598 }
599
600 #[test]
601 fn test_tanh() {
602 assert!((tanh(0.0, 0.0) - 0.0).abs() < 1e-10);
603 }
604
605 #[test]
606 fn test_sign() {
607 assert_eq!(sign(5.0, 0.0), 1.0);
608 assert_eq!(sign(-3.0, 0.0), -1.0);
609 assert_eq!(sign(0.0, 0.0), 0.0);
610 }
611}