1 // origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c
2 //
3 // ====================================================
4 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5 //
6 // Developed at SunPro, a Sun Microsystems, Inc. business.
7 // Permission to use, copy, modify, and distribute this
8 // software is freely granted, provided that this notice
9 // is preserved.
10 // ====================================================
11 //
12 // Optimized by Bruce D. Evans. */
13 use super::rem_pio2_large;
14 
15 // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
16 // #define EPS DBL_EPSILON
17 const EPS: f64 = 2.2204460492503131e-16;
18 // #elif FLT_EVAL_METHOD==2
19 // #define EPS LDBL_EPSILON
20 // #endif
21 
22 // TODO: Support FLT_EVAL_METHOD?
23 
24 const TO_INT: f64 = 1.5 / EPS;
25 /// 53 bits of 2/pi
26 const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */
27 /// first 33 bits of pi/2
28 const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */
29 /// pi/2 - PIO2_1
30 const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */
31 /// second 33 bits of pi/2
32 const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */
33 /// pi/2 - (PIO2_1+PIO2_2)
34 const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */
35 /// third 33 bits of pi/2
36 const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */
37 /// pi/2 - (PIO2_1+PIO2_2+PIO2_3)
38 const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
39 
40 // return the remainder of x rem pi/2 in y[0]+y[1]
41 // use rem_pio2_large() for large x
42 //
43 // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
44 #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
rem_pio2(x: f64) -> (i32, f64, f64)45 pub(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         /* rint(x/(pi/2)), Assume round-to-nearest. */
53         let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT;
54         let n = f_n as i32;
55         let mut r = x - f_n * PIO2_1;
56         let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */
57         let mut y0 = r - w;
58         let ui = f64::to_bits(y0);
59         let ey = (ui >> 52) as i32 & 0x7ff;
60         let ex = (ix >> 20) as i32;
61         if ex - ey > 16 {
62             /* 2nd round, good to 118 bits */
63             let t = r;
64             w = f_n * PIO2_2;
65             r = t - w;
66             w = f_n * PIO2_2T - ((t - r) - w);
67             y0 = r - w;
68             let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff;
69             if ex - ey > 49 {
70                 /* 3rd round, good to 151 bits, covers all cases */
71                 let t = r;
72                 w = f_n * PIO2_3;
73                 r = t - w;
74                 w = f_n * PIO2_3T - ((t - r) - w);
75                 y0 = r - w;
76             }
77         }
78         let y1 = (r - y0) - w;
79         (n, y0, y1)
80     }
81 
82     if ix <= 0x400f6a7a {
83         /* |x| ~<= 5pi/4 */
84         if (ix & 0xfffff) == 0x921fb {
85             /* |x| ~= pi/2 or 2pi/2 */
86             return medium(x, ix); /* cancellation -- use medium case */
87         }
88         if ix <= 0x4002d97c {
89             /* |x| ~<= 3pi/4 */
90             if sign == 0 {
91                 let z = x - PIO2_1; /* one round good to 85 bits */
92                 let y0 = z - PIO2_1T;
93                 let y1 = (z - y0) - PIO2_1T;
94                 return (1, y0, y1);
95             } else {
96                 let z = x + PIO2_1;
97                 let y0 = z + PIO2_1T;
98                 let y1 = (z - y0) + PIO2_1T;
99                 return (-1, y0, y1);
100             }
101         } else if sign == 0 {
102             let z = x - 2.0 * PIO2_1;
103             let y0 = z - 2.0 * PIO2_1T;
104             let y1 = (z - y0) - 2.0 * PIO2_1T;
105             return (2, y0, y1);
106         } else {
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         }
112     }
113     if ix <= 0x401c463b {
114         /* |x| ~<= 9pi/4 */
115         if ix <= 0x4015fdbc {
116             /* |x| ~<= 7pi/4 */
117             if ix == 0x4012d97c {
118                 /* |x| ~= 3pi/2 */
119                 return medium(x, ix);
120             }
121             if sign == 0 {
122                 let z = x - 3.0 * PIO2_1;
123                 let y0 = z - 3.0 * PIO2_1T;
124                 let y1 = (z - y0) - 3.0 * PIO2_1T;
125                 return (3, y0, y1);
126             } else {
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             }
132         } else {
133             if ix == 0x401921fb {
134                 /* |x| ~= 4pi/2 */
135                 return medium(x, ix);
136             }
137             if sign == 0 {
138                 let z = x - 4.0 * PIO2_1;
139                 let y0 = z - 4.0 * PIO2_1T;
140                 let y1 = (z - y0) - 4.0 * PIO2_1T;
141                 return (4, y0, y1);
142             } else {
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             }
148         }
149     }
150     if ix < 0x413921fb {
151         /* |x| ~< 2^20*(pi/2), medium size */
152         return medium(x, ix);
153     }
154     /*
155      * all other (large) arguments
156      */
157     if ix >= 0x7ff00000 {
158         /* x is inf or NaN */
159         let y0 = x - x;
160         let y1 = y0;
161         return (0, y0, y1);
162     }
163     /* set z = scalbn(|x|,-ilogb(x)+23) */
164     let mut ui = f64::to_bits(x);
165     ui &= (!1) >> 12;
166     ui |= (0x3ff + 23) << 52;
167     let mut z = f64::from_bits(ui);
168     let mut tx = [0.0; 3];
169     for i in 0..2 {
170         tx[i] = z as i32 as f64;
171         z = (z - tx[i]) * x1p24;
172     }
173     tx[2] = z;
174     /* skip zero terms, first term is non-zero */
175     let mut i = 2;
176     while i != 0 && tx[i] == 0.0 {
177         i -= 1;
178     }
179     let mut ty = [0.0; 3];
180     let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1);
181     if sign != 0 {
182         return (-n, -ty[0], -ty[1]);
183     }
184     (n, ty[0], ty[1])
185 }
186 
187 #[cfg(test)]
188 mod tests {
189     use super::rem_pio2;
190 
191     #[test]
test_near_pi()192     fn test_near_pi() {
193         assert_eq!(
194             rem_pio2(3.141592025756836),
195             (2, -6.278329573009626e-7, -2.1125998133974653e-23)
196         );
197         assert_eq!(
198             rem_pio2(3.141592033207416),
199             (2, -6.20382377148128e-7, -2.1125998133974653e-23)
200         );
201         assert_eq!(
202             rem_pio2(3.141592144966125),
203             (2, -5.086236681942706e-7, -2.1125998133974653e-23)
204         );
205         assert_eq!(
206             rem_pio2(3.141592979431152),
207             (2, 3.2584135866119817e-7, -2.1125998133974653e-23)
208         );
209     }
210 
211     #[test]
test_overflow_b9b847()212     fn test_overflow_b9b847() {
213         let _ = rem_pio2(-3054214.5490637687);
214     }
215 
216     #[test]
test_overflow_4747b9()217     fn test_overflow_4747b9() {
218         let _ = rem_pio2(917340800458.2274);
219     }
220 }
221