1use super::rem_pio2_large;
14
15const EPS: f64 = 2.2204460492503131e-16;
18const TO_INT: f64 = 1.5 / EPS;
25const INV_PIO2: f64 = 6.36619772367581382433e-01; const PIO2_1: f64 = 1.57079632673412561417e+00; const PIO2_1T: f64 = 6.07710050650619224932e-11; const PIO2_2: f64 = 6.07710050630396597660e-11; const PIO2_2T: f64 = 2.02226624879595063154e-21; const PIO2_3: f64 = 2.02226624871116645580e-21; const PIO2_3T: f64 = 8.47842766036889956997e-32; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
45pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) {
46    let x1p24 = f64::from_bits(0x4170000000000000);
47
48    let sign = (f64::to_bits(x) >> 63) as i32;
49    let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;
50
51    fn medium(x: f64, ix: u32) -> (i32, f64, f64) {
52        let tmp = x * INV_PIO2 + TO_INT;
54        #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
57        let tmp = force_eval!(tmp);
58        let f_n = tmp - TO_INT;
59        let n = f_n as i32;
60        let mut r = x - f_n * PIO2_1;
61        let mut w = f_n * PIO2_1T; let mut y0 = r - w;
63        let ui = f64::to_bits(y0);
64        let ey = (ui >> 52) as i32 & 0x7ff;
65        let ex = (ix >> 20) as i32;
66        if ex - ey > 16 {
67            let t = r;
69            w = f_n * PIO2_2;
70            r = t - w;
71            w = f_n * PIO2_2T - ((t - r) - w);
72            y0 = r - w;
73            let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff;
74            if ex - ey > 49 {
75                let t = r;
77                w = f_n * PIO2_3;
78                r = t - w;
79                w = f_n * PIO2_3T - ((t - r) - w);
80                y0 = r - w;
81            }
82        }
83        let y1 = (r - y0) - w;
84        (n, y0, y1)
85    }
86
87    if ix <= 0x400f6a7a {
88        if (ix & 0xfffff) == 0x921fb {
90            return medium(x, ix); }
93        if ix <= 0x4002d97c {
94            if sign == 0 {
96                let z = x - PIO2_1; let y0 = z - PIO2_1T;
98                let y1 = (z - y0) - PIO2_1T;
99                return (1, y0, y1);
100            } else {
101                let z = x + PIO2_1;
102                let y0 = z + PIO2_1T;
103                let y1 = (z - y0) + PIO2_1T;
104                return (-1, y0, y1);
105            }
106        } else if sign == 0 {
107            let z = x - 2.0 * PIO2_1;
108            let y0 = z - 2.0 * PIO2_1T;
109            let y1 = (z - y0) - 2.0 * PIO2_1T;
110            return (2, y0, y1);
111        } else {
112            let z = x + 2.0 * PIO2_1;
113            let y0 = z + 2.0 * PIO2_1T;
114            let y1 = (z - y0) + 2.0 * PIO2_1T;
115            return (-2, y0, y1);
116        }
117    }
118    if ix <= 0x401c463b {
119        if ix <= 0x4015fdbc {
121            if ix == 0x4012d97c {
123                return medium(x, ix);
125            }
126            if sign == 0 {
127                let z = x - 3.0 * PIO2_1;
128                let y0 = z - 3.0 * PIO2_1T;
129                let y1 = (z - y0) - 3.0 * PIO2_1T;
130                return (3, y0, y1);
131            } else {
132                let z = x + 3.0 * PIO2_1;
133                let y0 = z + 3.0 * PIO2_1T;
134                let y1 = (z - y0) + 3.0 * PIO2_1T;
135                return (-3, y0, y1);
136            }
137        } else {
138            if ix == 0x401921fb {
139                return medium(x, ix);
141            }
142            if sign == 0 {
143                let z = x - 4.0 * PIO2_1;
144                let y0 = z - 4.0 * PIO2_1T;
145                let y1 = (z - y0) - 4.0 * PIO2_1T;
146                return (4, y0, y1);
147            } else {
148                let z = x + 4.0 * PIO2_1;
149                let y0 = z + 4.0 * PIO2_1T;
150                let y1 = (z - y0) + 4.0 * PIO2_1T;
151                return (-4, y0, y1);
152            }
153        }
154    }
155    if ix < 0x413921fb {
156        return medium(x, ix);
158    }
159    if ix >= 0x7ff00000 {
163        let y0 = x - x;
165        let y1 = y0;
166        return (0, y0, y1);
167    }
168    let mut ui = f64::to_bits(x);
170    ui &= (!1) >> 12;
171    ui |= (0x3ff + 23) << 52;
172    let mut z = f64::from_bits(ui);
173    let mut tx = [0.0; 3];
174    for i in 0..2 {
175        i!(tx,i, =, z as i32 as f64);
176        z = (z - i!(tx, i)) * x1p24;
177    }
178    i!(tx,2, =, z);
179    let mut i = 2;
181    while i != 0 && i!(tx, i) == 0.0 {
182        i -= 1;
183    }
184    let mut ty = [0.0; 3];
185    let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1);
186    if sign != 0 {
187        return (-n, -i!(ty, 0), -i!(ty, 1));
188    }
189    (n, i!(ty, 0), i!(ty, 1))
190}
191
192#[cfg(test)]
193mod tests {
194    use super::rem_pio2;
195
196    #[test]
197    #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)]
199    fn test_near_pi() {
200        let arg = 3.141592025756836;
201        let arg = force_eval!(arg);
202        assert_eq!(
203            rem_pio2(arg),
204            (2, -6.278329573009626e-7, -2.1125998133974653e-23)
205        );
206        let arg = 3.141592033207416;
207        let arg = force_eval!(arg);
208        assert_eq!(
209            rem_pio2(arg),
210            (2, -6.20382377148128e-7, -2.1125998133974653e-23)
211        );
212        let arg = 3.141592144966125;
213        let arg = force_eval!(arg);
214        assert_eq!(
215            rem_pio2(arg),
216            (2, -5.086236681942706e-7, -2.1125998133974653e-23)
217        );
218        let arg = 3.141592979431152;
219        let arg = force_eval!(arg);
220        assert_eq!(
221            rem_pio2(arg),
222            (2, 3.2584135866119817e-7, -2.1125998133974653e-23)
223        );
224    }
225
226    #[test]
227    fn test_overflow_b9b847() {
228        let _ = rem_pio2(-3054214.5490637687);
229    }
230
231    #[test]
232    fn test_overflow_4747b9() {
233        let _ = rem_pio2(917340800458.2274);
234    }
235}