• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 use super::{get_high_word, k_cos, k_sin, rem_pio2};
14 
15 /// Both the sine and cosine of `x` (f64).
16 ///
17 /// `x` is specified in radians and the return value is (sin(x), cos(x)).
18 #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
sincos(x: f64) -> (f64, f64)19 pub fn sincos(x: f64) -> (f64, f64) {
20     let s: f64;
21     let c: f64;
22     let mut ix: u32;
23 
24     ix = get_high_word(x);
25     ix &= 0x7fffffff;
26 
27     /* |x| ~< pi/4 */
28     if ix <= 0x3fe921fb {
29         /* if |x| < 2**-27 * sqrt(2) */
30         if ix < 0x3e46a09e {
31             /* raise inexact if x!=0 and underflow if subnormal */
32             let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120
33             if ix < 0x00100000 {
34                 force_eval!(x / x1p120);
35             } else {
36                 force_eval!(x + x1p120);
37             }
38             return (x, 1.0);
39         }
40         return (k_sin(x, 0.0, 0), k_cos(x, 0.0));
41     }
42 
43     /* sincos(Inf or NaN) is NaN */
44     if ix >= 0x7ff00000 {
45         let rv = x - x;
46         return (rv, rv);
47     }
48 
49     /* argument reduction needed */
50     let (n, y0, y1) = rem_pio2(x);
51     s = k_sin(y0, y1, 1);
52     c = k_cos(y0, y1);
53     match n & 3 {
54         0 => (s, c),
55         1 => (c, -s),
56         2 => (-s, -c),
57         3 => (-c, s),
58         #[cfg(debug_assertions)]
59         _ => unreachable!(),
60         #[cfg(not(debug_assertions))]
61         _ => (0.0, 1.0),
62     }
63 }
64 
65 // These tests are based on those from sincosf.rs
66 #[cfg(test)]
67 mod tests {
68     use super::sincos;
69 
70     const TOLERANCE: f64 = 1e-6;
71 
72     #[test]
with_pi()73     fn with_pi() {
74         let (s, c) = sincos(core::f64::consts::PI);
75         assert!(
76             (s - 0.0).abs() < TOLERANCE,
77             "|{} - {}| = {} >= {}",
78             s,
79             0.0,
80             (s - 0.0).abs(),
81             TOLERANCE
82         );
83         assert!(
84             (c + 1.0).abs() < TOLERANCE,
85             "|{} + {}| = {} >= {}",
86             c,
87             1.0,
88             (s + 1.0).abs(),
89             TOLERANCE
90         );
91     }
92 
93     #[test]
rotational_symmetry()94     fn rotational_symmetry() {
95         use core::f64::consts::PI;
96         const N: usize = 24;
97         for n in 0..N {
98             let theta = 2. * PI * (n as f64) / (N as f64);
99             let (s, c) = sincos(theta);
100             let (s_plus, c_plus) = sincos(theta + 2. * PI);
101             let (s_minus, c_minus) = sincos(theta - 2. * PI);
102 
103             assert!(
104                 (s - s_plus).abs() < TOLERANCE,
105                 "|{} - {}| = {} >= {}",
106                 s,
107                 s_plus,
108                 (s - s_plus).abs(),
109                 TOLERANCE
110             );
111             assert!(
112                 (s - s_minus).abs() < TOLERANCE,
113                 "|{} - {}| = {} >= {}",
114                 s,
115                 s_minus,
116                 (s - s_minus).abs(),
117                 TOLERANCE
118             );
119             assert!(
120                 (c - c_plus).abs() < TOLERANCE,
121                 "|{} - {}| = {} >= {}",
122                 c,
123                 c_plus,
124                 (c - c_plus).abs(),
125                 TOLERANCE
126             );
127             assert!(
128                 (c - c_minus).abs() < TOLERANCE,
129                 "|{} - {}| = {} >= {}",
130                 c,
131                 c_minus,
132                 (c - c_minus).abs(),
133                 TOLERANCE
134             );
135         }
136     }
137 }
138