1/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
2/*
3 * ====================================================
4 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5 *
6 * Developed at SunPro, a Sun Microsystems, Inc. business.
7 * Permission to use, copy, modify, and distribute this
8 * software is freely granted, provided that this notice
9 * is preserved.
10 * ====================================================
11 */
12
13use super::{get_high_word, k_cos, k_sin, rem_pio2};
14
15#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
16pub fn sincos(x: f64) -> (f64, f64) {
17 let s: f64;
18 let c: f64;
19 let mut ix: u32;
20
21 ix = get_high_word(x);
22 ix &= 0x7fffffff;
23
24 /* |x| ~< pi/4 */
25 if ix <= 0x3fe921fb {
26 /* if |x| < 2**-27 * sqrt(2) */
27 if ix < 0x3e46a09e {
28 /* raise inexact if x!=0 and underflow if subnormal */
29 let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120
30 if ix < 0x00100000 {
31 force_eval!(x / x1p120);
32 } else {
33 force_eval!(x + x1p120);
34 }
35 return (x, 1.0);
36 }
37 return (k_sin(x, 0.0, 0), k_cos(x, 0.0));
38 }
39
40 /* sincos(Inf or NaN) is NaN */
41 if ix >= 0x7ff00000 {
42 let rv = x - x;
43 return (rv, rv);
44 }
45
46 /* argument reduction needed */
47 let (n, y0, y1) = rem_pio2(x);
48 s = k_sin(y0, y1, 1);
49 c = k_cos(y0, y1);
50 match n & 3 {
51 0 => (s, c),
52 1 => (c, -s),
53 2 => (-s, -c),
54 3 => (-c, s),
55 #[cfg(debug_assertions)]
56 _ => unreachable!(),
57 #[cfg(not(debug_assertions))]
58 _ => (0.0, 1.0),
59 }
60}
61
62// These tests are based on those from sincosf.rs
63#[cfg(test)]
64mod tests {
65 use super::sincos;
66
67 const TOLERANCE: f64 = 1e-6;
68
69 #[test]
70 fn with_pi() {
71 let (s, c) = sincos(core::f64::consts::PI);
72 assert!(
73 (s - 0.0).abs() < TOLERANCE,
74 "|{} - {}| = {} >= {}",
75 s,
76 0.0,
77 (s - 0.0).abs(),
78 TOLERANCE
79 );
80 assert!(
81 (c + 1.0).abs() < TOLERANCE,
82 "|{} + {}| = {} >= {}",
83 c,
84 1.0,
85 (s + 1.0).abs(),
86 TOLERANCE
87 );
88 }
89
90 #[test]
91 fn rotational_symmetry() {
92 use core::f64::consts::PI;
93 const N: usize = 24;
94 for n in 0..N {
95 let theta = 2. * PI * (n as f64) / (N as f64);
96 let (s, c) = sincos(theta);
97 let (s_plus, c_plus) = sincos(theta + 2. * PI);
98 let (s_minus, c_minus) = sincos(theta - 2. * PI);
99
100 assert!(
101 (s - s_plus).abs() < TOLERANCE,
102 "|{} - {}| = {} >= {}",
103 s,
104 s_plus,
105 (s - s_plus).abs(),
106 TOLERANCE
107 );
108 assert!(
109 (s - s_minus).abs() < TOLERANCE,
110 "|{} - {}| = {} >= {}",
111 s,
112 s_minus,
113 (s - s_minus).abs(),
114 TOLERANCE
115 );
116 assert!(
117 (c - c_plus).abs() < TOLERANCE,
118 "|{} - {}| = {} >= {}",
119 c,
120 c_plus,
121 (c - c_plus).abs(),
122 TOLERANCE
123 );
124 assert!(
125 (c - c_minus).abs() < TOLERANCE,
126 "|{} - {}| = {} >= {}",
127 c,
128 c_minus,
129 (c - c_minus).abs(),
130 TOLERANCE
131 );
132 }
133 }
134}
135