Skip to main content

c/
math_trig.rs

1// Copyright (c) 2026 Meng Zhuo
2// SPDX-License-Identifier: BSD-3-Clause
3
4// Translated from musl: sin, cos, tan, sinf, cosf, tanf,
5// __sin, __cos, __tan, __rem_pio2, __rem_pio2f, __rem_pio2_large,
6// __sindf, __cosdf, __tandf
7
8const INIT_JK: [i32; 4] = [3, 4, 4, 6];
9
10const IPIO2: [i32; 66] = [
11    0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
12    0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
13    0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
14    0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
15    0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
16    0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
17    0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
18    0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
19    0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
20    0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
21    0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
22];
23
24const PIO2: [f64; 8] = [
25    asdouble(0x3FF921FB40000000),
26    asdouble(0x3E74442D00000000),
27    asdouble(0x3CF8469880000000),
28    asdouble(0x3B78CC5160000000),
29    asdouble(0x39F01B8380000000),
30    asdouble(0x387A252040000000),
31    asdouble(0x36E3822280000000),
32    asdouble(0x3569F31D00000000),
33];
34
35const S1PIO2: f64 = asdouble(0x3FF921FB54442D18);
36const S2PIO2: f64 = asdouble(0x400921FB54442D18);
37const S3PIO2: f64 = asdouble(0x4012D97C7F3321D2);
38const S4PIO2: f64 = asdouble(0x401921FB54442D18);
39
40#[allow(non_snake_case)]
41fn __rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, nx: i32, prec: i32) -> i32 {
42    let mut iq = [0i32; 20];
43    let mut f = [0.0f64; 30];
44    let mut fq = [0.0f64; 20];
45    let mut q = [0.0f64; 20];
46
47    let jk = INIT_JK[prec as usize];
48    let jp = jk;
49    let jx = nx - 1;
50    let mut jv = (e0 - 3) / 24;
51    if jv < 0 { jv = 0; }
52    let mut q0 = e0 - 24 * (jv + 1);
53
54    let mut j = jv - jx;
55    let m = jx + jk;
56    for ii in 0..=m {
57        f[ii as usize] = if j < 0 { 0.0 } else { IPIO2[j as usize] as f64 };
58        j += 1;
59    }
60
61    for ii in 0..=jk {
62        let mut fw = 0.0f64;
63        for jj in 0..=jx {
64            fw += x[jj as usize] * f[(jx + ii - jj) as usize];
65        }
66        q[ii as usize] = fw;
67    }
68
69    let mut jz = jk;
70    let mut need_recompute = true;
71    let mut n_val = 0i32;
72    let mut ih_val = 0i32;
73    let mut z = 0.0f64;
74
75    while need_recompute {
76        need_recompute = false;
77        // distill q[] into iq[]
78        z = q[jz as usize];
79        j = jz;
80        let mut ii = 0i32;
81        while j > 0 {
82            let fw = (z * p2d(-24)) as i32;
83            iq[ii as usize] = (z - fw as f64 * p2d(24)) as i32;
84            z = q[(j - 1) as usize] + fw as f64;
85            ii += 1;
86            j -= 1;
87        }
88
89        z = scalbn(z, q0);
90        z -= 8.0 * floor(z * 0.125);
91        n_val = z as i32;
92        z -= n_val as f64;
93        ih_val = 0;
94        if q0 > 0 {
95            let i_part = iq[(jz - 1) as usize] >> (24 - q0);
96            n_val += i_part;
97            iq[(jz - 1) as usize] -= i_part << (24 - q0);
98            ih_val = iq[(jz - 1) as usize] >> (23 - q0);
99        } else if q0 == 0 {
100            ih_val = iq[(jz - 1) as usize] >> 23;
101        } else if z >= 0.5 {
102            ih_val = 2;
103        }
104
105        if ih_val > 0 {
106            n_val += 1;
107            let mut carry = 0i32;
108            for idx in 0..(jz as usize) {
109                let jv = iq[idx];
110                if carry == 0 {
111                    if jv != 0 {
112                        carry = 1;
113                        iq[idx] = 0x1000000 - jv;
114                    }
115                } else {
116                    iq[idx] = 0xffffff - jv;
117                }
118            }
119            if q0 > 0 {
120                match q0 {
121                    1 => { iq[(jz - 1) as usize] &= 0x7fffff; }
122                    2 => { iq[(jz - 1) as usize] &= 0x3fffff; }
123                    _ => {}
124                }
125            }
126            if ih_val == 2 {
127                z = 1.0 - z;
128                if carry != 0 {
129                    z -= scalbn(1.0, q0);
130                }
131            }
132        }
133
134        // check recomputation
135        if z == 0.0 {
136            j = 0;
137            let mut idx = jz - 1;
138            while idx >= jk {
139                j |= iq[idx as usize];
140                idx -= 1;
141            }
142            if j == 0 {
143                let mut k = 1i32;
144                while iq[(jk - k) as usize] == 0 { k += 1; }
145                for idx2 in (jz + 1)..=(jz + k) {
146                    f[(jx + idx2) as usize] = IPIO2[(jv + idx2) as usize] as f64;
147                    let mut fw = 0.0f64;
148                    for jj in 0..=jx {
149                        fw += x[jj as usize] * f[(jx + idx2 - jj) as usize];
150                    }
151                    q[idx2 as usize] = fw;
152                }
153                jz += k;
154                need_recompute = true;
155            }
156        }
157    }
158
159    // chop off zero terms
160    if z == 0.0 {
161        jz -= 1;
162        q0 -= 24;
163        while iq[jz as usize] == 0 {
164            jz -= 1;
165            q0 -= 24;
166        }
167    } else {
168        z = scalbn(z, -q0);
169        if z >= p2d(24) {
170            let fw = (z * p2d(-24)) as i32;
171            iq[jz as usize] = (z - fw as f64 * p2d(24)) as i32;
172            jz += 1;
173            q0 += 24;
174            iq[jz as usize] = fw;
175        } else {
176            iq[jz as usize] = z as i32;
177        }
178    }
179
180    // convert integer chunks to float
181    let mut fw = scalbn(1.0, q0);
182    for idx in (0..=(jz as usize)).rev() {
183        q[idx] = fw * iq[idx] as f64;
184        fw *= p2d(-24);
185    }
186
187    // compute PIo2 * q
188    for idx in (0..=(jz as usize)).rev() {
189        fw = 0.0;
190        for k in 0..=(jp as usize) {
191            if k <= (jz as usize - idx) {
192                fw += PIO2[k] * q[idx + k];
193            }
194        }
195        fq[(jz as usize) - idx] = fw;
196    }
197
198    // compress fq[] into y[]
199    match prec {
200        0 => {
201            fw = 0.0;
202            for idx in (0..=(jz as usize)).rev() {
203                fw += fq[idx];
204            }
205            y[0] = if ih_val == 0 { fw } else { -fw };
206        }
207        1 | 2 => {
208            fw = 0.0;
209            for idx in (0..=(jz as usize)).rev() {
210                fw += fq[idx];
211            }
212            fw = fw; // double_t = f64 when FLT_EVAL_METHOD==0
213            y[0] = if ih_val == 0 { fw } else { -fw };
214            fw = fq[0] - fw;
215            for idx in 1..=(jz as usize) {
216                fw += fq[idx];
217            }
218            y[1] = if ih_val == 0 { fw } else { -fw };
219        }
220        _ => {
221            for idx in (1..=(jz as usize)).rev() {
222                let tmp = fq[idx - 1] + fq[idx];
223                fq[idx] += fq[idx - 1] - tmp;
224                fq[idx - 1] = tmp;
225            }
226            for idx in (2..=(jz as usize)).rev() {
227                let tmp = fq[idx - 1] + fq[idx];
228                fq[idx] += fq[idx - 1] - tmp;
229                fq[idx - 1] = tmp;
230            }
231            fw = 0.0;
232            for idx in (2..=(jz as usize)).rev() {
233                fw += fq[idx];
234            }
235            if ih_val == 0 {
236                y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
237            } else {
238                y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
239            }
240        }
241    }
242    n_val & 7
243}
244
245const REM_PIO2_TOINT: f64 = asdouble(0x4338000000000000);
246const REM_PIO2_PIO4: f64 = asdouble(0x3FE921FB54442D18);
247const REM_PIO2_INVPIO2: f64 = asdouble(0x3FE45F306DC9C883);
248const REM_PIO2_PIO2_1: f64 = asdouble(0x3FF921FB54400000);
249const REM_PIO2_PIO2_1T: f64 = asdouble(0x3DD0B4611A626331);
250const REM_PIO2_PIO2_2: f64 = asdouble(0x3DD0B4611A600000);
251const REM_PIO2_PIO2_2T: f64 = asdouble(0x3BA3198A2E037073);
252const REM_PIO2_PIO2_3: f64 = asdouble(0x3BA3198A2E000000);
253const REM_PIO2_PIO2_3T: f64 = asdouble(0x397B839A252049C1);
254
255fn __rem_pio2(x: f64, y: &mut [f64; 2]) -> i32 {
256    let ix64 = asuint64(x);
257    let sign = (ix64 >> 63) as i32;
258    let ix = ((ix64 >> 32) & 0x7fffffff) as u32;
259
260    if ix <= 0x400f6a7a {
261        if (ix & 0xfffff) == 0x921fb {
262            // cancellation -- use medium case
263            return rem_pio2_medium(x, sign, ix, y);
264        }
265        if ix <= 0x4002d97c {
266            if sign == 0 {
267                let z = x - REM_PIO2_PIO2_1;
268                y[0] = z - REM_PIO2_PIO2_1T;
269                y[1] = (z - y[0]) - REM_PIO2_PIO2_1T;
270                return 1;
271            } else {
272                let z = x + REM_PIO2_PIO2_1;
273                y[0] = z + REM_PIO2_PIO2_1T;
274                y[1] = (z - y[0]) + REM_PIO2_PIO2_1T;
275                return -1;
276            }
277        } else {
278            if sign == 0 {
279                let z = x - 2.0 * REM_PIO2_PIO2_1;
280                y[0] = z - 2.0 * REM_PIO2_PIO2_1T;
281                y[1] = (z - y[0]) - 2.0 * REM_PIO2_PIO2_1T;
282                return 2;
283            } else {
284                let z = x + 2.0 * REM_PIO2_PIO2_1;
285                y[0] = z + 2.0 * REM_PIO2_PIO2_1T;
286                y[1] = (z - y[0]) + 2.0 * REM_PIO2_PIO2_1T;
287                return -2;
288            }
289        }
290    }
291    if ix <= 0x401c463b {
292        if ix <= 0x4015fdbc {
293            if ix == 0x4012d97c {
294                return rem_pio2_medium(x, sign, ix, y);
295            }
296            if sign == 0 {
297                let z = x - 3.0 * REM_PIO2_PIO2_1;
298                y[0] = z - 3.0 * REM_PIO2_PIO2_1T;
299                y[1] = (z - y[0]) - 3.0 * REM_PIO2_PIO2_1T;
300                return 3;
301            } else {
302                let z = x + 3.0 * REM_PIO2_PIO2_1;
303                y[0] = z + 3.0 * REM_PIO2_PIO2_1T;
304                y[1] = (z - y[0]) + 3.0 * REM_PIO2_PIO2_1T;
305                return -3;
306            }
307        } else {
308            if ix == 0x401921fb {
309                return rem_pio2_medium(x, sign, ix, y);
310            }
311            if sign == 0 {
312                let z = x - 4.0 * REM_PIO2_PIO2_1;
313                y[0] = z - 4.0 * REM_PIO2_PIO2_1T;
314                y[1] = (z - y[0]) - 4.0 * REM_PIO2_PIO2_1T;
315                return 4;
316            } else {
317                let z = x + 4.0 * REM_PIO2_PIO2_1;
318                y[0] = z + 4.0 * REM_PIO2_PIO2_1T;
319                y[1] = (z - y[0]) + 4.0 * REM_PIO2_PIO2_1T;
320                return -4;
321            }
322        }
323    }
324    if ix < 0x413921fb {
325        return rem_pio2_medium(x, sign, ix, y);
326    }
327    // all other (large) arguments
328    if ix >= 0x7ff00000 {
329        y[0] = x - x;
330        y[1] = y[0];
331        return 0;
332    }
333    // set z = scalbn(|x|,-ilogb(x)+23)
334    let mut ux = ix64;
335    ux &= (-1i64 as u64) >> 12;
336    ux |= ((0x3ff + 23) as u64) << 52;
337    let mut z = asdouble(ux);
338    let mut tx = [0.0f64; 3];
339    for i in 0..2 {
340        tx[i] = z as i32 as f64;
341        z = (z - tx[i]) * p2d(24);
342    }
343    tx[2] = z;
344    let mut i = 2i32;
345    while tx[i as usize] == 0.0 {
346        i -= 1;
347    }
348    let n = __rem_pio2_large(&tx, y, (ix >> 20) as i32 - (0x3ff + 23), i + 1, 1);
349    if sign != 0 {
350        y[0] = -y[0];
351        y[1] = -y[1];
352        return -(n as i32);
353    }
354    n as i32
355}
356
357fn rem_pio2_medium(x: f64, _sign: i32, ix: u32, y: &mut [f64; 2]) -> i32 {
358    let mut fn_val = x as f64 * REM_PIO2_INVPIO2 + REM_PIO2_TOINT - REM_PIO2_TOINT;
359    let mut n = fn_val as i32;
360    let mut r = x - fn_val * REM_PIO2_PIO2_1;
361    let mut w = fn_val * REM_PIO2_PIO2_1T;
362    if predict_false(r - w < -REM_PIO2_PIO4) {
363        n -= 1;
364        fn_val -= 1.0;
365        r = x - fn_val * REM_PIO2_PIO2_1;
366        w = fn_val * REM_PIO2_PIO2_1T;
367    } else if predict_false(r - w > REM_PIO2_PIO4) {
368        n += 1;
369        fn_val += 1.0;
370        r = x - fn_val * REM_PIO2_PIO2_1;
371        w = fn_val * REM_PIO2_PIO2_1T;
372    }
373    y[0] = r - w;
374    let ey = ((asuint64(y[0]) >> 52) & 0x7ff) as i32;
375    let ex = (ix >> 20) as i32;
376    if ex - ey > 16 {
377        let t = r;
378        w = fn_val * REM_PIO2_PIO2_2;
379        r = t - w;
380        w = fn_val * REM_PIO2_PIO2_2T - ((t - r) - w);
381        y[0] = r - w;
382        let ey = ((asuint64(y[0]) >> 52) & 0x7ff) as i32;
383        if ex - ey > 49 {
384            let t = r;
385            w = fn_val * REM_PIO2_PIO2_3;
386            r = t - w;
387            w = fn_val * REM_PIO2_PIO2_3T - ((t - r) - w);
388            y[0] = r - w;
389        }
390    }
391    y[1] = (r - y[0]) - w;
392    n
393}
394
395const REMPIO2F_TOINT: f64 = asdouble(0x4338000000000000);
396const REMPIO2F_PIO4: f64 = asdouble(0x3FE921FB60000000);
397const REMPIO2F_INVPIO2: f64 = asdouble(0x3FE45F306DC9C883);
398const REMPIO2F_PIO2_1: f64 = asdouble(0x3FF921FB50000000);
399const REMPIO2F_PIO2_1T: f64 = asdouble(0x3E5110B4611A6263);
400
401fn __rem_pio2f(x: f32, y: &mut f64) -> i32 {
402    let ix = asuint(x) & 0x7fffffff;
403    if ix < 0x4dc90fdb {
404        let mut fn_val = x as f64 * REMPIO2F_INVPIO2 + REMPIO2F_TOINT - REMPIO2F_TOINT;
405        let mut n = fn_val as i32;
406        *y = x as f64 - fn_val * REMPIO2F_PIO2_1 - fn_val * REMPIO2F_PIO2_1T;
407        if predict_false(*y < -REMPIO2F_PIO4) {
408            n -= 1;
409            fn_val -= 1.0;
410            *y = x as f64 - fn_val * REMPIO2F_PIO2_1 - fn_val * REMPIO2F_PIO2_1T;
411        } else if predict_false(*y > REMPIO2F_PIO4) {
412            n += 1;
413            fn_val += 1.0;
414            *y = x as f64 - fn_val * REMPIO2F_PIO2_1 - fn_val * REMPIO2F_PIO2_1T;
415        }
416        return n;
417    }
418    if ix >= 0x7f800000 {
419        *y = x as f64 - x as f64;
420        return 0;
421    }
422    let sign = (asuint(x) >> 31) as i32;
423    let e0 = ((ix >> 23) as i32) - (0x7f + 23);
424    let ux = ix - ((e0 as u32) << 23);
425    let tx = [asfloat(ux) as f64];
426    let mut ty = [0.0f64];
427    let n = __rem_pio2_large(&tx, &mut ty, e0, 1, 0);
428    if sign != 0 {
429        *y = -ty[0];
430        return -(n as i32);
431    }
432    *y = ty[0];
433    n as i32
434}
435
436// __sin kernel
437const SIN_S1: f64 = asdouble(0xBFC5555555555549);
438const SIN_S2: f64 = asdouble(0x3F8111111110F8A6);
439const SIN_S3: f64 = asdouble(0xBF2A01A019C161D5);
440const SIN_S4: f64 = asdouble(0x3EC71DE357B1FE7D);
441const SIN_S5: f64 = asdouble(0xBE5AE5E68A2B9CEB);
442const SIN_S6: f64 = asdouble(0x3DE5D93A5ACFD57C);
443
444fn __sin(x: f64, y: f64, iy: i32) -> f64 {
445    let z = x * x;
446    let w = z * z;
447    let r = SIN_S2 + z * (SIN_S3 + z * SIN_S4) + z * w * (SIN_S5 + z * SIN_S6);
448    let v = z * x;
449    if iy == 0 {
450        x + v * (SIN_S1 + z * r)
451    } else {
452        x - ((z * (0.5 * y - v * r) - y) - v * SIN_S1)
453    }
454}
455
456// __cos kernel
457const COS_C1: f64 = asdouble(0x3FA555555555554C);
458const COS_C2: f64 = asdouble(0xBF56C16C16C15177);
459const COS_C3: f64 = asdouble(0x3EFA01A019CB1590);
460const COS_C4: f64 = asdouble(0xBE927E4F809C52AD);
461const COS_C5: f64 = asdouble(0x3E21EE9EBDB4B1C4);
462const COS_C6: f64 = asdouble(0xBDA8FAE9BE8838D4);
463
464fn __cos(x: f64, y: f64) -> f64 {
465    let z = x * x;
466    let w = z * z;
467    let r = z * (COS_C1 + z * (COS_C2 + z * COS_C3)) + w * w * (COS_C4 + z * (COS_C5 + z * COS_C6));
468    let hz = 0.5 * z;
469    let w = 1.0 - hz;
470    w + (((1.0 - w) - hz) + (z * r - x * y))
471}
472
473// __tan kernel
474const TAN_T: [f64; 13] = [
475    asdouble(0x3FD5555555555563),
476    asdouble(0x3FC111111110FE7A),
477    asdouble(0x3FABA1BA1BB341FE),
478    asdouble(0x3F9664F48406D637),
479    asdouble(0x3F8226E3E96E8493),
480    asdouble(0x3F6D6D22C9560328),
481    asdouble(0x3F57DBC8FEE08315),
482    asdouble(0x3F4344D8F2F26501),
483    asdouble(0x3F3026F71A8D1068),
484    asdouble(0x3F147E88A03792A6),
485    asdouble(0x3F12B80F32F0A7E9),
486    asdouble(0xBEF375CBDB605373),
487    asdouble(0x3EFB2A7074BF7AD4),
488];
489const TAN_PIO4: f64 = asdouble(0x3FE921FB54442D18);
490const TAN_PIO4LO: f64 = asdouble(0x3C81A62633145C07);
491
492fn __tan(x: f64, y: f64, odd: i32) -> f64 {
493    let hx = (asuint64(x) >> 32) as u32;
494    let big = (hx & 0x7fffffff) >= 0x3FE59428;
495    let (x, y, sign) = if big {
496        let sign = hx >> 31;
497        let (nx, ny) = if sign != 0 { (-x, -y) } else { (x, y) };
498        ((TAN_PIO4 - nx) + (TAN_PIO4LO - ny), 0.0, sign)
499    } else {
500        (x, y, 0u32)
501    };
502    let z = x * x;
503    let w = z * z;
504    let r = TAN_T[1] + w * (TAN_T[3] + w * (TAN_T[5] + w * (TAN_T[7] + w * (TAN_T[9] + w * TAN_T[11]))));
505    let v = z * (TAN_T[2] + w * (TAN_T[4] + w * (TAN_T[6] + w * (TAN_T[8] + w * (TAN_T[10] + w * TAN_T[12])))));
506    let s = z * x;
507    let r = y + z * (s * (r + v) + y) + s * TAN_T[0];
508    let w = x + r;
509    if big {
510        let s_val = 1.0 - 2.0 * odd as f64;
511        let v = s_val - 2.0 * (x + (r - w * w / (w + s_val)));
512        return if sign != 0 { -v } else { v };
513    }
514    if odd == 0 {
515        return w;
516    }
517    // -1.0/(x+r) has up to 2ulp error, so compute it accurately
518    let w0 = {
519        let mut tmp = w;
520        unsafe { set_low_word(&mut tmp, 0); }
521        tmp
522    };
523    let v = r - (w0 - x);
524    let mut a0 = -1.0 / w;
525    let a = a0;
526    unsafe { set_low_word(&mut a0, 0); }
527    a0 + a * (1.0 + a0 * w0 + a0 * v)
528}
529
530// __sindf kernel
531const SINDF_S1: f64 = asdouble(0xBFC5555554CBAC77);
532const SINDF_S2: f64 = asdouble(0x3F811110896EFBB2);
533const SINDF_S3: f64 = asdouble(0xBF2A00F9E2CAE774);
534const SINDF_S4: f64 = asdouble(0x3EC6CD878C3B46A7);
535
536fn __sindf(x: f64) -> f32 {
537    let z = x * x;
538    let w = z * z;
539    let r = SINDF_S3 + z * SINDF_S4;
540    let s = z * x;
541    ((x + s * (SINDF_S1 + z * SINDF_S2)) + s * w * r) as f32
542}
543
544// __cosdf kernel
545const COSDF_C0: f64 = asdouble(0xBFDFFFFFFD0C5E81);
546const COSDF_C1: f64 = asdouble(0x3FA55553E1053A42);
547const COSDF_C2: f64 = asdouble(0xBF56C087E80F1E27);
548const COSDF_C3: f64 = asdouble(0x3EF99342E0EE5069);
549
550fn __cosdf(x: f64) -> f32 {
551    let z = x * x;
552    let w = z * z;
553    let r = COSDF_C2 + z * COSDF_C3;
554    ((1.0 + z * COSDF_C0) + w * COSDF_C1 + (w * z) * r) as f32
555}
556
557// __tandf kernel
558const TANDF_T: [f64; 6] = [
559    asdouble(0x3FD5554D3418C99F),
560    asdouble(0x3FC112FD38999F72),
561    asdouble(0x3FAB54C91D865AFE),
562    asdouble(0x3F991DF3908C33CE),
563    asdouble(0x3F685DADFCECF44E),
564    asdouble(0x3F8362B9BF971BCD),
565];
566
567fn __tandf(x: f64, odd: i32) -> f32 {
568    let z = x * x;
569    let r = TANDF_T[4] + z * TANDF_T[5];
570    let t = TANDF_T[2] + z * TANDF_T[3];
571    let w = z * z;
572    let s = z * x;
573    let u = TANDF_T[0] + z * TANDF_T[1];
574    let r = (x + s * u) + (s * w) * (t + w * r);
575    if odd != 0 { (-1.0 / r) as f32 } else { r as f32 }
576}
577
578// ============================================================
579// sin, cos, tan (double precision)
580// ============================================================
581
582#[no_mangle]
583pub extern "C" fn sin(x: f64) -> f64 {
584    let mut ix = (asuint64(x) >> 32) as u32;
585    ix &= 0x7fffffff;
586
587    if ix <= 0x3fe921fb {
588        if ix < 0x3e500000 {
589            force_eval(if ix < 0x00100000 { x / p2f(120) as f64 } else { x + p2f(120) as f64 });
590            return x;
591        }
592        return __sin(x, 0.0, 0);
593    }
594    if ix >= 0x7ff00000 {
595        return x - x;
596    }
597    let mut y = [0.0f64; 2];
598    let n = __rem_pio2(x, &mut y);
599    match n & 3 {
600        0 =>  __sin(y[0], y[1], 1),
601        1 =>  __cos(y[0], y[1]),
602        2 => -__sin(y[0], y[1], 1),
603        _ => -__cos(y[0], y[1]),
604    }
605}
606
607#[no_mangle]
608pub extern "C" fn cos(x: f64) -> f64 {
609    let mut ix = (asuint64(x) >> 32) as u32;
610    ix &= 0x7fffffff;
611
612    if ix <= 0x3fe921fb {
613        if ix < 0x3e46a09e {
614            force_eval(x + p2f(120) as f64);
615            return 1.0;
616        }
617        return __cos(x, 0.0);
618    }
619    if ix >= 0x7ff00000 {
620        return x - x;
621    }
622    let mut y = [0.0f64; 2];
623    let n = __rem_pio2(x, &mut y);
624    match n & 3 {
625        0 =>  __cos(y[0], y[1]),
626        1 => -__sin(y[0], y[1], 1),
627        2 => -__cos(y[0], y[1]),
628        _ =>  __sin(y[0], y[1], 1),
629    }
630}
631
632#[no_mangle]
633pub extern "C" fn tan(x: f64) -> f64 {
634    let mut ix = (asuint64(x) >> 32) as u32;
635    ix &= 0x7fffffff;
636
637    if ix <= 0x3fe921fb {
638        if ix < 0x3e400000 {
639            force_eval(if ix < 0x00100000 { x / p2f(120) as f64 } else { x + p2f(120) as f64 });
640            return x;
641        }
642        return __tan(x, 0.0, 0);
643    }
644    if ix >= 0x7ff00000 {
645        return x - x;
646    }
647    let mut y = [0.0f64; 2];
648    let n = __rem_pio2(x, &mut y);
649    __tan(y[0], y[1], n & 1)
650}
651
652// ============================================================
653// sinf, cosf, tanf (single precision)
654// ============================================================
655
656#[no_mangle]
657pub extern "C" fn sinf(x: f32) -> f32 {
658    let ix = asuint(x);
659    let sign = ix >> 31;
660    let ix = ix & 0x7fffffff;
661
662    if ix <= 0x3f490fda {
663        if ix < 0x39800000 {
664            force_eval(if ix < 0x00800000 { x / p2f(120) } else { x + p2f(120) });
665            return x;
666        }
667        return __sindf(x as f64);
668    }
669    if ix <= 0x407b53d1 {
670        if ix <= 0x4016cbe3 {
671            return if sign != 0 { -__cosdf(x as f64 + S1PIO2) } else { __cosdf(x as f64 - S1PIO2) };
672        }
673        return __sindf(if sign != 0 { -(x as f64 + S2PIO2) } else { -(x as f64 - S2PIO2) });
674    }
675    if ix <= 0x40e231d5 {
676        if ix <= 0x40afeddf {
677            return if sign != 0 { __cosdf(x as f64 + S3PIO2) } else { -__cosdf(x as f64 - S3PIO2) };
678        }
679        return __sindf(if sign != 0 { x as f64 + S4PIO2 } else { x as f64 - S4PIO2 });
680    }
681    if ix >= 0x7f800000 {
682        return x - x;
683    }
684    let mut y = 0.0f64;
685    let n = __rem_pio2f(x, &mut y);
686    match n & 3 {
687        0 =>  __sindf(y),
688        1 =>  __cosdf(y),
689        2 =>  __sindf(-y),
690        _ => -__cosdf(y),
691    }
692}
693
694#[no_mangle]
695pub extern "C" fn cosf(x: f32) -> f32 {
696    let ix = asuint(x);
697    let sign = ix >> 31;
698    let ix = ix & 0x7fffffff;
699
700    if ix <= 0x3f490fda {
701        if ix < 0x39800000 {
702            force_eval(x + p2f(120));
703            return 1.0f32;
704        }
705        return __cosdf(x as f64);
706    }
707    if ix <= 0x407b53d1 {
708        if ix > 0x4016cbe3 {
709            return -__cosdf(if sign != 0 { x as f64 + S2PIO2 } else { x as f64 - S2PIO2 });
710        } else {
711            return if sign != 0 { __sindf(x as f64 + S1PIO2) } else { __sindf(S1PIO2 - x as f64) };
712        }
713    }
714    if ix <= 0x40e231d5 {
715        if ix > 0x40afeddf {
716            return __cosdf(if sign != 0 { x as f64 + S4PIO2 } else { x as f64 - S4PIO2 });
717        } else {
718            return if sign != 0 { __sindf(-x as f64 - S3PIO2) } else { __sindf(x as f64 - S3PIO2) };
719        }
720    }
721    if ix >= 0x7f800000 {
722        return x - x;
723    }
724    let mut y = 0.0f64;
725    let n = __rem_pio2f(x, &mut y);
726    match n & 3 {
727        0 =>  __cosdf(y),
728        1 =>  __sindf(-y),
729        2 => -__cosdf(y),
730        _ =>  __sindf(y),
731    }
732}
733
734#[no_mangle]
735pub extern "C" fn tanf(x: f32) -> f32 {
736    let ix = asuint(x);
737    let sign = ix >> 31;
738    let ix = ix & 0x7fffffff;
739
740    if ix <= 0x3f490fda {
741        if ix < 0x39800000 {
742            force_eval(if ix < 0x00800000 { x / p2f(120) } else { x + p2f(120) });
743            return x;
744        }
745        return __tandf(x as f64, 0);
746    }
747    if ix <= 0x407b53d1 {
748        if ix <= 0x4016cbe3 {
749            return __tandf(if sign != 0 { x as f64 + S1PIO2 } else { x as f64 - S1PIO2 }, 1);
750        } else {
751            return __tandf(if sign != 0 { x as f64 + S2PIO2 } else { x as f64 - S2PIO2 }, 0);
752        }
753    }
754    if ix <= 0x40e231d5 {
755        if ix <= 0x40afeddf {
756            return __tandf(if sign != 0 { x as f64 + S3PIO2 } else { x as f64 - S3PIO2 }, 1);
757        } else {
758            return __tandf(if sign != 0 { x as f64 + S4PIO2 } else { x as f64 - S4PIO2 }, 0);
759        }
760    }
761    if ix >= 0x7f800000 {
762        return x - x;
763    }
764    let mut y = 0.0f64;
765    let n = __rem_pio2f(x, &mut y);
766    __tandf(y, n & 1)
767}