1use crate::bits::EXP_MASK;
30use crate::common::{dyad_fmla, f_fmla};
31use crate::double_double::DoubleDouble;
32use crate::sin::range_reduction_small;
33use crate::sincos_reduce::LargeArgumentReduction;
34use crate::tangent::tanpi_table::TAN_K_PI_OVER_128;
35
36#[inline]
37pub(crate) fn tan_eval(u: DoubleDouble) -> (DoubleDouble, f64) {
38 let u_hi_sq = u.hi * u.hi; let p1 = f_fmla(
52 u_hi_sq,
53 f64::from_bits(0x3f9664f4882c10fa),
54 f64::from_bits(0x3faba1ba1ba1ba1c),
55 );
56 let p2 = f_fmla(
58 u_hi_sq,
59 f64::from_bits(0x3fc1111111111111),
60 f64::from_bits(0x3fd5555555555555),
61 );
62 let q1 = f_fmla(u_hi_sq, f64::from_bits(0x3fe5555555555555), 1.0);
64 let u_hi_3 = u_hi_sq * u.hi;
65 let u_hi_4 = u_hi_sq * u_hi_sq;
66 let p3 = f_fmla(u_hi_4, p1, p2);
68 let q2 = f_fmla(u_hi_sq, q1, 1.0);
70 let tan_lo = f_fmla(u_hi_3, p3, u.lo * q2);
71 let err = f_fmla(
75 u_hi_3.abs(),
76 f64::from_bits(0x3cc0000000000000),
77 f64::from_bits(0x3990000000000000),
78 );
79 (DoubleDouble::from_exact_add(u.hi, tan_lo), err)
80}
81
82#[inline]
83pub(crate) fn tan_eval_dd(x: DoubleDouble) -> DoubleDouble {
84 const C: [(u64, u64); 7] = [
89 (0x0000000000000000, 0x3ff0000000000000),
90 (0x3c75555549d35a4b, 0x3fd5555555555555),
91 (0x3c413dd6ea580288, 0x3fc1111111111111),
92 (0x3c4e100b946f0c89, 0x3faba1ba1ba1b9fe),
93 (0xbc3c180dfac2b8c3, 0x3f9664f488307189),
94 (0x3c1fd691c256a14a, 0x3f8226e300c1988e),
95 (0x3bec7b08c90fdfc0, 0x3f6d739baeacd204),
96 ];
97 let x2 = DoubleDouble::quick_mult(x, x);
98 let mut p = DoubleDouble::quick_mul_add(
99 x2,
100 DoubleDouble::from_bit_pair(C[6]),
101 DoubleDouble::from_bit_pair(C[5]),
102 );
103 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[4]));
104 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[3]));
105 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[2]));
106 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[1]));
107 p = DoubleDouble::quick_mul_add_f64(x2, p, f64::from_bits(0x3ff0000000000000));
108 let r = DoubleDouble::quick_mult(p, x);
109 DoubleDouble::from_exact_add(r.hi, r.lo)
110}
111
112#[cold]
113fn tan_accurate(y: DoubleDouble, tan_k: DoubleDouble) -> f64 {
114 let tan_y = tan_eval_dd(y);
117
118 let num_dd = DoubleDouble::full_dd_add(tan_y, tan_k);
120 let den_dd = DoubleDouble::mul_add_f64(tan_y, -tan_k, 1.);
122
123 let tan_x = DoubleDouble::div(num_dd, den_dd);
124 tan_x.to_f64()
125}
126
127#[cold]
128fn tan_near_zero_hard(x: f64) -> DoubleDouble {
129 const C: [(u64, u64); 7] = [
134 (0x0000000000000000, 0x3ff0000000000000),
135 (0x3c7555548455da94, 0x3fd5555555555555),
136 (0x3c4306a6358cc810, 0x3fc1111111111111),
137 (0x3c2ca9cd025ea98c, 0x3faba1ba1ba1b952),
138 (0x3c3cb012803c55a5, 0x3f9664f4883eb962),
139 (0x3c28afc1adb8f202, 0x3f8226e276097461),
140 (0xbbdf8f911392f348, 0x3f6d7791601277ea),
141 ];
142 let x2 = DoubleDouble::from_exact_mult(x, x);
143 let mut p = DoubleDouble::quick_mul_add(
144 x2,
145 DoubleDouble::from_bit_pair(C[6]),
146 DoubleDouble::from_bit_pair(C[5]),
147 );
148 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[4]));
149 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[3]));
150 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[2]));
151 p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[1]));
152 p = DoubleDouble::quick_mul_add_f64(x2, p, f64::from_bits(0x3ff0000000000000));
153 DoubleDouble::quick_mult_f64(p, x)
154}
155
156pub fn f_tan(x: f64) -> f64 {
160 let x_e = (x.to_bits() >> 52) & 0x7ff;
161 const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64;
162
163 let y: DoubleDouble;
164 let k;
165
166 let mut argument_reduction = LargeArgumentReduction::default();
167
168 if x_e < E_BIAS + 16 {
169 if x_e < E_BIAS - 5 {
171 if x_e < E_BIAS - 27 {
173 if x == 0.0 {
175 return x + x;
177 }
178 return dyad_fmla(x, f64::from_bits(0x3c90000000000000), x);
179 }
180 let x2 = x * x;
181 let x4 = x2 * x2;
182 const C: [u64; 4] = [
187 0x3fd555555555554b,
188 0x3fc1111111142d5b,
189 0x3faba1b9860ed843,
190 0x3f966a802210f5bb,
191 ];
192 let p01 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0]));
193 let p23 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2]));
194 let w0 = f_fmla(x4, p23, p01);
195 let w1 = x2 * w0 * x;
196 let r = DoubleDouble::from_exact_add(x, w1);
197 let err = f_fmla(
198 x2,
199 f64::from_bits(0x3cb0000000000000), f64::from_bits(0x3be0000000000000), );
202 let ub = r.hi + (r.lo + err);
203 let lb = r.hi + (r.lo - err);
204 if ub == lb {
205 return ub;
206 }
207 return tan_near_zero_hard(x).to_f64();
208 } else {
209 (y, k) = range_reduction_small(x);
211 }
212 } else {
213 if x_e > 2 * E_BIAS {
215 if x.is_nan() {
216 return f64::NAN;
217 }
218 return x + f64::NAN;
220 }
221
222 (k, y) = argument_reduction.reduce(x);
224 }
225
226 let (tan_y, err) = tan_eval(y);
227
228 let tan_k = DoubleDouble::from_bit_pair(TAN_K_PI_OVER_128[(k & 255) as usize]);
231
232 let num_dd = DoubleDouble::add(tan_y, tan_k);
234 let den_dd = DoubleDouble::mul_add_f64(tan_y, -tan_k, 1.);
236
237 let tan_x = DoubleDouble::div(num_dd, den_dd);
238
239 let den_inv = ((E_BIAS + 1) << (52 + 1)) - (den_dd.hi.to_bits() & EXP_MASK);
241 let tan_err = err * f_fmla(f64::from_bits(den_inv), tan_x.hi.abs(), 1.0);
244
245 let err_higher = tan_x.lo + tan_err;
246 let err_lower = tan_x.lo - tan_err;
247
248 let tan_upper = tan_x.hi + err_higher;
249 let tan_lower = tan_x.hi + err_lower;
250
251 if tan_upper == tan_lower {
253 return tan_upper;
254 }
255
256 tan_accurate(y, tan_k)
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn tan_test() {
265 assert_eq!(f_tan(0.0003242153424), 0.0003242153537600293);
266 assert_eq!(f_tan(-0.3242153424), -0.3360742441422686);
267 assert_eq!(f_tan(0.3242153424), 0.3360742441422686);
268 assert_eq!(f_tan(-97301943219974110.), 0.000000000000000481917514979303);
269 assert_eq!(f_tan(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007291122019556397),
270 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007291122019556397);
271 assert_eq!(f_tan(0.0), 0.0);
272 assert_eq!(f_tan(0.4324324324), 0.4615683710506729);
273 assert_eq!(f_tan(1.0), 1.5574077246549023);
274 assert_eq!(f_tan(-0.5), -0.5463024898437905);
275 assert!(f_tan(f64::INFINITY).is_nan());
276 assert!(f_tan(f64::NEG_INFINITY).is_nan());
277 assert!(f_tan(f64::NAN).is_nan());
278 }
279}