const_soft_float/soft_f64/cos.rs
1// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */,
2// https://github.com/rust-lang/libm/blob/4c8a973741c014b11ce7f1477693a3e5d4ef9609/src/math/cos.rs
3//
4// ====================================================
5// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6//
7// Developed at SunPro, a Sun Microsystems, Inc. business.
8// Permission to use, copy, modify, and distribute this
9// software is freely granted, provided that this notice
10// is preserved.
11// ====================================================
12
13use super::{
14 helpers::{k_cos, k_sin, rem_pio2},
15 SoftF64,
16};
17
18// cos(x)
19// Return cosine function of x.
20//
21// kernel function:
22// k_sin ... sine function on [-pi/4,pi/4]
23// k_cos ... cosine function on [-pi/4,pi/4]
24// rem_pio2 ... argument reduction routine
25//
26// Method.
27// Let S,C and T denote the sin, cos and tan respectively on
28// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
29// in [-pi/4 , +pi/4], and let n = k mod 4.
30// We have
31//
32// n sin(x) cos(x) tan(x)
33// ----------------------------------------------------------
34// 0 S C T
35// 1 C -S -1/T
36// 2 -S -C T
37// 3 -C S -1/T
38// ----------------------------------------------------------
39//
40// Special cases:
41// Let trig be any of sin, cos, or tan.
42// trig(+-INF) is NaN, with signals;
43// trig(NaN) is that NaN;
44//
45// Accuracy:
46// TRIG(x) returns trig(x) nearly rounded
47//
48pub(crate) const fn cos(x: SoftF64) -> SoftF64 {
49 let ix = (SoftF64::to_bits(x) >> 32) as u32 & 0x7fffffff;
50
51 /* |x| ~< pi/4 */
52 if ix <= 0x3fe921fb {
53 if ix < 0x3e46a09e {
54 /* if x < 2**-27 * sqrt(2) */
55 /* raise inexact if x != 0 */
56 if x.0 as i32 == 0 {
57 return SoftF64::ONE;
58 }
59 }
60 return k_cos(x, SoftF64::ZERO);
61 }
62
63 /* cos(Inf or NaN) is NaN */
64 if ix >= 0x7ff00000 {
65 return x.sub(x);
66 }
67
68 /* argument reduction needed */
69 let (n, y0, y1) = rem_pio2(x);
70 match n & 3 {
71 0 => k_cos(y0, y1),
72 1 => k_sin(y0, y1, 1).neg(),
73 2 => k_cos(y0, y1).neg(),
74 _ => k_sin(y0, y1, 1),
75 }
76}
77
78#[cfg(test)]
79mod test {
80 use crate::soft_f64::SoftF64;
81
82 #[test]
83 fn test_large_neg() {
84 assert_eq!(SoftF64(-1647101.0).cos().to_f64(), (-1647101.0_f64).cos())
85 }
86}