Skip to main content

deep_time/math/
rem_pio2.rs

1#![allow(clippy::indexing_slicing)]
2#![allow(clippy::excessive_precision)]
3#![allow(clippy::approx_constant)]
4#![allow(clippy::eq_op)]
5
6// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c
7//
8// ====================================================
9// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
10//
11// Developed at SunPro, a Sun Microsystems, Inc. business.
12// Permission to use, copy, modify, and distribute this
13// software is freely granted, provided that this notice
14// is preserved.
15// ====================================================
16//
17// Optimized by Bruce D. Evans. */
18use super::rem_pio2_large;
19use crate::Real;
20
21// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
22// #define EPS DBL_EPSILON
23const EPS: Real = 2.2204460492503131e-16;
24// #elif FLT_EVAL_METHOD==2
25// #define EPS LDBL_EPSILON
26// #endif
27
28const TO_INT: Real = 1.5 / EPS;
29/// 53 bits of 2/pi
30const INV_PIO2: Real = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */
31/// first 33 bits of pi/2
32const PIO2_1: Real = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */
33/// pi/2 - PIO2_1
34const PIO2_1T: Real = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */
35/// second 33 bits of pi/2
36const PIO2_2: Real = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */
37/// pi/2 - (PIO2_1+PIO2_2)
38const PIO2_2T: Real = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */
39/// third 33 bits of pi/2
40const PIO2_3: Real = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */
41/// pi/2 - (PIO2_1+PIO2_2+PIO2_3)
42const PIO2_3T: Real = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
43
44// return the remainder of x rem pi/2 in y[0]+y[1]
45// use rem_pio2_large() for large x
46//
47// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
48pub(crate) const fn rem_pio2(x: Real) -> (i32, Real, Real) {
49    let x1p24 = Real::from_bits(0x4170000000000000);
50
51    let sign = (Real::to_bits(x) >> 63) as i32;
52    let ix = (Real::to_bits(x) >> 32) as u32 & 0x7fffffff;
53
54    const fn medium(x: Real, ix: u32) -> (i32, Real, Real) {
55        let tmp = x * INV_PIO2 + TO_INT;
56        let f_n = tmp - TO_INT;
57        let n = f_n as i32;
58        let mut r = x - f_n * PIO2_1;
59        let mut w = f_n * PIO2_1T;
60        let mut y0 = r - w;
61        let ui = Real::to_bits(y0);
62        let ey = (ui >> 52) as i32 & 0x7ff;
63        let ex = (ix >> 20) as i32;
64
65        if ex - ey > 16 {
66            let t = r;
67            w = f_n * PIO2_2;
68            r = t - w;
69            w = f_n * PIO2_2T - ((t - r) - w);
70            y0 = r - w;
71            let ey = (Real::to_bits(y0) >> 52) as i32 & 0x7ff;
72            if ex - ey > 49 {
73                let t = r;
74                w = f_n * PIO2_3;
75                r = t - w;
76                w = f_n * PIO2_3T - ((t - r) - w);
77                y0 = r - w;
78            }
79        }
80        let y1 = (r - y0) - w;
81        (n, y0, y1)
82    }
83
84    // Very small values are handled in sin/cos before calling rem_pio2
85
86    if ix <= 0x400f6a7a {
87        /* |x| ~<= 5π/4 */
88        if (ix & 0xfffff) == 0x921fb {
89            return medium(x, ix);
90        }
91        // Use medium() for better accuracy instead of single-round special cases
92        return medium(x, ix);
93    }
94
95    if ix <= 0x401c463b {
96        /* |x| ~<= 9π/4 */
97        if ix == 0x4012d97c || ix == 0x401921fb {
98            return medium(x, ix);
99        }
100        // Use medium() for better accuracy
101        return medium(x, ix);
102    }
103
104    if ix < 0x413921fb {
105        /* |x| ~< 2^20 * (π/2) */
106        return medium(x, ix);
107    }
108
109    /* Large arguments */
110    if ix >= 0x7ff00000 {
111        let y0 = x - x;
112        let y1 = y0;
113        return (0, y0, y1);
114    }
115
116    /* Very large arguments -> use rem_pio2_large */
117    let mut ui = Real::to_bits(x);
118    ui &= (!1) >> 12;
119    ui |= (0x3ff + 23) << 52;
120    let mut z = Real::from_bits(ui);
121
122    let mut tx = [0.0; 3];
123    let mut i: usize = 0;
124    while i < 2 {
125        tx[i] = z as i32 as Real;
126        z = (z - tx[i]) * x1p24;
127        i += 1;
128    }
129    tx[2] = z;
130
131    let mut i = 2;
132    while i != 0 && tx[i] == 0.0 {
133        i -= 1;
134    }
135
136    let mut ty = [0.0; 3];
137    let n = rem_pio2_large(&tx, i + 1, &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1);
138
139    if sign != 0 {
140        return (-n, -ty[0], -ty[1]);
141    }
142    (n, ty[0], ty[1])
143}