Skip to content

Commit 4c0992b

Browse files
bors[bot]porglezomp
andcommitted
80: Add sin and cos r=japaric a=porglezomp Closes rust-lang#11 Closes rust-lang#33 Co-authored-by: C Jones <[email protected]>
2 parents 297df8b + 4fb6e33 commit 4c0992b

File tree

9 files changed

+476
-11
lines changed

9 files changed

+476
-11
lines changed

src/lib.rs

-4
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,8 @@ pub trait F64Ext: private::Sealed {
386386

387387
fn hypot(self, other: Self) -> Self;
388388

389-
#[cfg(todo)]
390389
fn sin(self) -> Self;
391390

392-
#[cfg(todo)]
393391
fn cos(self) -> Self;
394392

395393
#[cfg(todo)]
@@ -548,13 +546,11 @@ impl F64Ext for f64 {
548546
hypot(self, other)
549547
}
550548

551-
#[cfg(todo)]
552549
#[inline]
553550
fn sin(self) -> Self {
554551
sin(self)
555552
}
556553

557-
#[cfg(todo)]
558554
#[inline]
559555
fn cos(self) -> Self {
560556
cos(self)

src/math/cos.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// origin: FreeBSD /usr/src/lib/msun/src/s_cos.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+
use super::{k_cos, k_sin, rem_pio2};
13+
14+
// cos(x)
15+
// Return cosine function of x.
16+
//
17+
// kernel function:
18+
// k_sin ... sine function on [-pi/4,pi/4]
19+
// k_cos ... cosine function on [-pi/4,pi/4]
20+
// rem_pio2 ... argument reduction routine
21+
//
22+
// Method.
23+
// Let S,C and T denote the sin, cos and tan respectively on
24+
// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
25+
// in [-pi/4 , +pi/4], and let n = k mod 4.
26+
// We have
27+
//
28+
// n sin(x) cos(x) tan(x)
29+
// ----------------------------------------------------------
30+
// 0 S C T
31+
// 1 C -S -1/T
32+
// 2 -S -C T
33+
// 3 -C S -1/T
34+
// ----------------------------------------------------------
35+
//
36+
// Special cases:
37+
// Let trig be any of sin, cos, or tan.
38+
// trig(+-INF) is NaN, with signals;
39+
// trig(NaN) is that NaN;
40+
//
41+
// Accuracy:
42+
// TRIG(x) returns trig(x) nearly rounded
43+
//
44+
pub fn cos(x: f64) -> f64 {
45+
let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;
46+
47+
/* |x| ~< pi/4 */
48+
if ix <= 0x3fe921fb {
49+
if ix < 0x3e46a09e {
50+
/* if x < 2**-27 * sqrt(2) */
51+
/* raise inexact if x != 0 */
52+
if x as i32 == 0 {
53+
return 1.0;
54+
}
55+
}
56+
return k_cos(x, 0.0);
57+
}
58+
59+
/* cos(Inf or NaN) is NaN */
60+
if ix >= 0x7ff00000 {
61+
return x - x;
62+
}
63+
64+
/* argument reduction needed */
65+
let (n, y0, y1) = rem_pio2(x);
66+
match n & 3 {
67+
0 => k_cos(y0, y1),
68+
1 => -k_sin(y0, y1, 1),
69+
2 => -k_cos(y0, y1),
70+
_ => k_sin(y0, y1, 1),
71+
}
72+
}

src/math/exp2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2525
// SUCH DAMAGE.
2626

27-
use super::scalbn::scalbn;
27+
use super::scalbn;
2828

2929
const TBLSIZE: usize = 256;
3030

src/math/k_cos.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c
2+
//
3+
// ====================================================
4+
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5+
//
6+
// Developed at SunSoft, 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+
const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */
13+
const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */
14+
const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */
15+
const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */
16+
const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */
17+
const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
18+
19+
// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
20+
// Input x is assumed to be bounded by ~pi/4 in magnitude.
21+
// Input y is the tail of x.
22+
//
23+
// Algorithm
24+
// 1. Since cos(-x) = cos(x), we need only to consider positive x.
25+
// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
26+
// 3. cos(x) is approximated by a polynomial of degree 14 on
27+
// [0,pi/4]
28+
// 4 14
29+
// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
30+
// where the remez error is
31+
//
32+
// | 2 4 6 8 10 12 14 | -58
33+
// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
34+
// | |
35+
//
36+
// 4 6 8 10 12 14
37+
// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
38+
// cos(x) ~ 1 - x*x/2 + r
39+
// since cos(x+y) ~ cos(x) - sin(x)*y
40+
// ~ cos(x) - x*y,
41+
// a correction term is necessary in cos(x) and hence
42+
// cos(x+y) = 1 - (x*x/2 - (r - x*y))
43+
// For better accuracy, rearrange to
44+
// cos(x+y) ~ w + (tmp + (r-x*y))
45+
// where w = 1 - x*x/2 and tmp is a tiny correction term
46+
// (1 - x*x/2 == w + tmp exactly in infinite precision).
47+
// The exactness of w + tmp in infinite precision depends on w
48+
// and tmp having the same precision as x. If they have extra
49+
// precision due to compiler bugs, then the extra precision is
50+
// only good provided it is retained in all terms of the final
51+
// expression for cos(). Retention happens in all cases tested
52+
// under FreeBSD, so don't pessimize things by forcibly clipping
53+
// any extra precision in w.
54+
#[inline]
55+
pub fn k_cos(x: f64, y: f64) -> f64 {
56+
let z = x * x;
57+
let w = z * z;
58+
let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6));
59+
let hz = 0.5 * z;
60+
let w = 1.0 - hz;
61+
w + (((1.0 - w) - hz) + (z * r - x * y))
62+
}

src/math/k_sin.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c
2+
//
3+
// ====================================================
4+
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5+
//
6+
// Developed at SunSoft, 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+
const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */
13+
const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */
14+
const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */
15+
const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */
16+
const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */
17+
const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
18+
19+
// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
20+
// Input x is assumed to be bounded by ~pi/4 in magnitude.
21+
// Input y is the tail of x.
22+
// Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
23+
//
24+
// Algorithm
25+
// 1. Since sin(-x) = -sin(x), we need only to consider positive x.
26+
// 2. Callers must return sin(-0) = -0 without calling here since our
27+
// odd polynomial is not evaluated in a way that preserves -0.
28+
// Callers may do the optimization sin(x) ~ x for tiny x.
29+
// 3. sin(x) is approximated by a polynomial of degree 13 on
30+
// [0,pi/4]
31+
// 3 13
32+
// sin(x) ~ x + S1*x + ... + S6*x
33+
// where
34+
//
35+
// |sin(x) 2 4 6 8 10 12 | -58
36+
// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
37+
// | x |
38+
//
39+
// 4. sin(x+y) = sin(x) + sin'(x')*y
40+
// ~ sin(x) + (1-x*x/2)*y
41+
// For better accuracy, let
42+
// 3 2 2 2 2
43+
// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
44+
// then 3 2
45+
// sin(x) = x + (S1*x + (x *(r-y/2)+y))
46+
#[inline]
47+
pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 {
48+
let z = x * x;
49+
let w = z * z;
50+
let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
51+
let v = z * x;
52+
if iy == 0 {
53+
x + v * (S1 + z * r)
54+
} else {
55+
x - ((z * (0.5 * y - v * r) - y) - v * S1)
56+
}
57+
}

src/math/mod.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ macro_rules! force_eval {
66
};
77
}
88

9+
// Public modules
910
mod acos;
1011
mod acosf;
1112
mod asin;
@@ -15,6 +16,7 @@ mod cbrt;
1516
mod cbrtf;
1617
mod ceil;
1718
mod ceilf;
19+
mod cos;
1820
mod cosf;
1921
mod exp;
2022
mod exp2;
@@ -46,6 +48,7 @@ mod round;
4648
mod roundf;
4749
mod scalbn;
4850
mod scalbnf;
51+
mod sin;
4952
mod sinf;
5053
mod sqrt;
5154
mod sqrtf;
@@ -63,6 +66,7 @@ pub use self::cbrt::cbrt;
6366
pub use self::cbrtf::cbrtf;
6467
pub use self::ceil::ceil;
6568
pub use self::ceilf::ceilf;
69+
pub use self::cos::cos;
6670
pub use self::cosf::cosf;
6771
pub use self::exp::exp;
6872
pub use self::exp2::exp2;
@@ -94,23 +98,33 @@ pub use self::round::round;
9498
pub use self::roundf::roundf;
9599
pub use self::scalbn::scalbn;
96100
pub use self::scalbnf::scalbnf;
101+
pub use self::sin::sin;
97102
pub use self::sinf::sinf;
98103
pub use self::sqrt::sqrt;
99104
pub use self::sqrtf::sqrtf;
100105
pub use self::tanf::tanf;
101106
pub use self::trunc::trunc;
102107
pub use self::truncf::truncf;
103108

109+
// Private modules
110+
mod k_cos;
104111
mod k_cosf;
112+
mod k_sin;
105113
mod k_sinf;
106114
mod k_tanf;
115+
mod rem_pio2;
107116
mod rem_pio2_large;
108117
mod rem_pio2f;
109118

110-
use self::{
111-
k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large,
112-
rem_pio2f::rem_pio2f,
113-
};
119+
// Private re-imports
120+
use self::k_cos::k_cos;
121+
use self::k_cosf::k_cosf;
122+
use self::k_sin::k_sin;
123+
use self::k_sinf::k_sinf;
124+
use self::k_tanf::k_tanf;
125+
use self::rem_pio2::rem_pio2;
126+
use self::rem_pio2_large::rem_pio2_large;
127+
use self::rem_pio2f::rem_pio2f;
114128

115129
#[inline]
116130
pub fn get_high_word(x: f64) -> u32 {

0 commit comments

Comments
 (0)