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)] |
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 tmp = x as f64 * INV_PIO2 + TO_INT; |
54 | // force rounding of tmp to it's storage format on x87 to avoid |
55 | // excess precision issues. |
56 | #[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; /* 1st round, good to 85 bits */ |
62 | 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 | /* 2nd round, good to 118 bits */ |
68 | 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 | /* 3rd round, good to 151 bits, covers all cases */ |
76 | 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 | /* |x| ~<= 5pi/4 */ |
89 | if (ix & 0xfffff) == 0x921fb { |
90 | /* |x| ~= pi/2 or 2pi/2 */ |
91 | return medium(x, ix); /* cancellation -- use medium case */ |
92 | } |
93 | if ix <= 0x4002d97c { |
94 | /* |x| ~<= 3pi/4 */ |
95 | if sign == 0 { |
96 | let z = x - PIO2_1; /* one round good to 85 bits */ |
97 | 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 | /* |x| ~<= 9pi/4 */ |
120 | if ix <= 0x4015fdbc { |
121 | /* |x| ~<= 7pi/4 */ |
122 | if ix == 0x4012d97c { |
123 | /* |x| ~= 3pi/2 */ |
124 | 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 | /* |x| ~= 4pi/2 */ |
140 | 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 | /* |x| ~< 2^20*(pi/2), medium size */ |
157 | return medium(x, ix); |
158 | } |
159 | /* |
160 | * all other (large) arguments |
161 | */ |
162 | if ix >= 0x7ff00000 { |
163 | /* x is inf or NaN */ |
164 | let y0 = x - x; |
165 | let y1 = y0; |
166 | return (0, y0, y1); |
167 | } |
168 | /* set z = scalbn(|x|,-ilogb(x)+23) */ |
169 | 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 | /* skip zero terms, first term is non-zero */ |
180 | 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)] |
193 | mod tests { |
194 | use super::rem_pio2; |
195 | |
196 | #[test ] |
197 | fn test_near_pi() { |
198 | let arg = 3.141592025756836; |
199 | let arg = force_eval!(arg); |
200 | assert_eq!( |
201 | rem_pio2(arg), |
202 | (2, -6.278329573009626e-7, -2.1125998133974653e-23) |
203 | ); |
204 | let arg = 3.141592033207416; |
205 | let arg = force_eval!(arg); |
206 | assert_eq!( |
207 | rem_pio2(arg), |
208 | (2, -6.20382377148128e-7, -2.1125998133974653e-23) |
209 | ); |
210 | let arg = 3.141592144966125; |
211 | let arg = force_eval!(arg); |
212 | assert_eq!( |
213 | rem_pio2(arg), |
214 | (2, -5.086236681942706e-7, -2.1125998133974653e-23) |
215 | ); |
216 | let arg = 3.141592979431152; |
217 | let arg = force_eval!(arg); |
218 | assert_eq!( |
219 | rem_pio2(arg), |
220 | (2, 3.2584135866119817e-7, -2.1125998133974653e-23) |
221 | ); |
222 | } |
223 | |
224 | #[test ] |
225 | fn test_overflow_b9b847() { |
226 | let _ = rem_pio2(-3054214.5490637687); |
227 | } |
228 | |
229 | #[test ] |
230 | fn test_overflow_4747b9() { |
231 | let _ = rem_pio2(917340800458.2274); |
232 | } |
233 | } |
234 | |