1use crate::common::{f_fmla, min_normal_f64};
30use crate::round::RoundFinite;
31
32pub(crate) static SIN_K_PI_OVER_64: [u64; 128] = [
39 0x0000000000000000,
40 0x3fa91f65f10dd814,
41 0x3fb917a6bc29b42c,
42 0x3fc2c8106e8e613a,
43 0x3fc8f8b83c69a60b,
44 0x3fcf19f97b215f1b,
45 0x3fd294062ed59f06,
46 0x3fd58f9a75ab1fdd,
47 0x3fd87de2a6aea963,
48 0x3fdb5d1009e15cc0,
49 0x3fde2b5d3806f63b,
50 0x3fe073879922ffee,
51 0x3fe1c73b39ae68c8,
52 0x3fe30ff7fce17035,
53 0x3fe44cf325091dd6,
54 0x3fe57d69348ceca0,
55 0x3fe6a09e667f3bcd,
56 0x3fe7b5df226aafaf,
57 0x3fe8bc806b151741,
58 0x3fe9b3e047f38741,
59 0x3fea9b66290ea1a3,
60 0x3feb728345196e3e,
61 0x3fec38b2f180bdb1,
62 0x3feced7af43cc773,
63 0x3fed906bcf328d46,
64 0x3fee212104f686e5,
65 0x3fee9f4156c62dda,
66 0x3fef0a7efb9230d7,
67 0x3fef6297cff75cb0,
68 0x3fefa7557f08a517,
69 0x3fefd88da3d12526,
70 0x3feff621e3796d7e,
71 0x3ff0000000000000,
72 0x3feff621e3796d7e,
73 0x3fefd88da3d12526,
74 0x3fefa7557f08a517,
75 0x3fef6297cff75cb0,
76 0x3fef0a7efb9230d7,
77 0x3fee9f4156c62dda,
78 0x3fee212104f686e5,
79 0x3fed906bcf328d46,
80 0x3feced7af43cc773,
81 0x3fec38b2f180bdb1,
82 0x3feb728345196e3e,
83 0x3fea9b66290ea1a3,
84 0x3fe9b3e047f38741,
85 0x3fe8bc806b151741,
86 0x3fe7b5df226aafaf,
87 0x3fe6a09e667f3bcd,
88 0x3fe57d69348ceca0,
89 0x3fe44cf325091dd6,
90 0x3fe30ff7fce17035,
91 0x3fe1c73b39ae68c8,
92 0x3fe073879922ffee,
93 0x3fde2b5d3806f63b,
94 0x3fdb5d1009e15cc0,
95 0x3fd87de2a6aea963,
96 0x3fd58f9a75ab1fdd,
97 0x3fd294062ed59f06,
98 0x3fcf19f97b215f1b,
99 0x3fc8f8b83c69a60b,
100 0x3fc2c8106e8e613a,
101 0x3fb917a6bc29b42c,
102 0x3fa91f65f10dd814,
103 0xb69f77598338bfdf,
104 0xbfa91f65f10dd814,
105 0xbfb917a6bc29b42c,
106 0xbfc2c8106e8e613a,
107 0xbfc8f8b83c69a60b,
108 0xbfcf19f97b215f1b,
109 0xbfd294062ed59f06,
110 0xbfd58f9a75ab1fdd,
111 0xbfd87de2a6aea963,
112 0xbfdb5d1009e15cc0,
113 0xbfde2b5d3806f63b,
114 0xbfe073879922ffee,
115 0xbfe1c73b39ae68c8,
116 0xbfe30ff7fce17035,
117 0xbfe44cf325091dd6,
118 0xbfe57d69348ceca0,
119 0xbfe6a09e667f3bcd,
120 0xbfe7b5df226aafaf,
121 0xbfe8bc806b151741,
122 0xbfe9b3e047f38741,
123 0xbfea9b66290ea1a3,
124 0xbfeb728345196e3e,
125 0xbfec38b2f180bdb1,
126 0xbfeced7af43cc773,
127 0xbfed906bcf328d46,
128 0xbfee212104f686e5,
129 0xbfee9f4156c62dda,
130 0xbfef0a7efb9230d7,
131 0xbfef6297cff75cb0,
132 0xbfefa7557f08a517,
133 0xbfefd88da3d12526,
134 0xbfeff621e3796d7e,
135 0xbff0000000000000,
136 0xbfeff621e3796d7e,
137 0xbfefd88da3d12526,
138 0xbfefa7557f08a517,
139 0xbfef6297cff75cb0,
140 0xbfef0a7efb9230d7,
141 0xbfee9f4156c62dda,
142 0xbfee212104f686e5,
143 0xbfed906bcf328d46,
144 0xbfeced7af43cc773,
145 0xbfec38b2f180bdb1,
146 0xbfeb728345196e3e,
147 0xbfea9b66290ea1a3,
148 0xbfe9b3e047f38741,
149 0xbfe8bc806b151741,
150 0xbfe7b5df226aafaf,
151 0xbfe6a09e667f3bcd,
152 0xbfe57d69348ceca0,
153 0xbfe44cf325091dd6,
154 0xbfe30ff7fce17035,
155 0xbfe1c73b39ae68c8,
156 0xbfe073879922ffee,
157 0xbfde2b5d3806f63b,
158 0xbfdb5d1009e15cc0,
159 0xbfd87de2a6aea963,
160 0xbfd58f9a75ab1fdd,
161 0xbfd294062ed59f06,
162 0xbfcf19f97b215f1b,
163 0xbfc8f8b83c69a60b,
164 0xbfc2c8106e8e613a,
165 0xbfb917a6bc29b42c,
166 0xbfa91f65f10dd814,
167];
168
169#[inline]
170pub(crate) fn reduce_small_pi64(x: f64) -> (f64, i64) {
171 const MPI_OVER_SIXTY_FOUR: [u64; 3] =
181 [0xbfa921fb54400000, 0xbd80b4611a600000, 0xbb53198a2e037073];
182 const SIXTY_EIGHT_OVER_PI: f64 = f64::from_bits(0x40345f306dc9c883);
183 let prod_hi = x * SIXTY_EIGHT_OVER_PI;
184 let kd = prod_hi.round_finite();
185
186 let y_hi = f_fmla(kd, f64::from_bits(MPI_OVER_SIXTY_FOUR[0]), x); let u_hi = f_fmla(kd, f64::from_bits(MPI_OVER_SIXTY_FOUR[1]), y_hi);
192 (u_hi, unsafe {
193 kd.to_int_unchecked::<i64>() })
195}
196
197struct SinCosPi64 {
198 v_sin: f64,
199 v_cos: f64,
200}
201
202#[inline]
203fn sincos_eval_pi64(x: f64) -> SinCosPi64 {
204 let x2 = x * x;
205 let x4 = x2 * x2;
206
207 const S: [u64; 4] = [
212 0x3ff0000000000000,
213 0xbfc5555555555451,
214 0x3f8111111072c563,
215 0xbf2a01321c030841,
216 ];
217
218 let s0 = f_fmla(x2, f64::from_bits(S[1]), f64::from_bits(S[0]));
219 let s1 = f_fmla(x2, f64::from_bits(S[3]), f64::from_bits(S[2]));
220 let v_sin = f_fmla(x4, s1, s0) * x;
221
222 const C: [u64; 4] = [
227 0x3ff0000000000000,
228 0xbfdffffffffffb6c,
229 0x3fa5555553f117c1,
230 0xbf56c0f056672a03,
231 ];
232 let c0 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0]));
233 let c1 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2]));
234 let v_cos = f_fmla(x4, c1, c0);
235
236 SinCosPi64 { v_sin, v_cos }
237}
238
239#[inline]
240pub(crate) fn sin_small(z: f64) -> f64 {
241 let x_e = (z.to_bits() >> 52) & 0x7ff;
242 const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64;
243
244 if x_e < E_BIAS - 26 {
245 return f_fmla(z, f64::from_bits(0xbc90000000000000), z);
246 }
247
248 let (angle_dd, k) = reduce_small_pi64(z);
249 let sin_cos = sincos_eval_pi64(angle_dd);
250
251 let sk = SIN_K_PI_OVER_64[((k as u64) & 127) as usize];
253 let ck = SIN_K_PI_OVER_64[(((k as u64).wrapping_add(32)) & 127) as usize];
254
255 let sin_k = f64::from_bits(sk);
256 let cos_k = f64::from_bits(ck);
257 f_fmla(sin_cos.v_cos, sin_k, sin_cos.v_sin * cos_k)
258}
259
260#[inline]
261pub(crate) fn cos_small(z: f64) -> f64 {
262 let x_e = (z.to_bits() >> 52) & 0x7ff;
263 const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64;
264
265 if x_e < E_BIAS - 27 {
266 if z == 0.0 {
268 return 1.0;
269 }
270 return 1.0 - min_normal_f64();
272 }
273
274 let (angle_dd, k) = reduce_small_pi64(z);
275
276 let sin_cos = sincos_eval_pi64(angle_dd);
277
278 let sk = SIN_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize];
280 let ck = SIN_K_PI_OVER_64[(((k as u64).wrapping_add(32)) & 127) as usize];
281
282 let sin_k = f64::from_bits(sk);
283 let cos_k = f64::from_bits(ck);
284 f_fmla(sin_cos.v_cos, cos_k, sin_cos.v_sin * sin_k)
285}