1use crate::common::{dd_fmla, f_fmla};
30use crate::double_double::DoubleDouble;
31use crate::exponents::auxiliary::fast_ldexp;
32use crate::exponents::exp::{EXP_REDUCE_T0, EXP_REDUCE_T1, to_denormal};
33use crate::round_ties_even::RoundTiesEven;
34
35#[inline]
36fn exp2_poly_dd(z: f64) -> DoubleDouble {
37 const C: [(u64, u64); 6] = [
38 (0x3bbabc9e3b39873e, 0x3f262e42fefa39ef),
39 (0xbae5e43a53e44950, 0x3e4ebfbdff82c58f),
40 (0xba0d3a15710d3d83, 0x3d6c6b08d704a0c0),
41 (0x3914dd5d2a5e025a, 0x3c83b2ab6fba4e77),
42 (0xb83dc47e47beb9dd, 0x3b95d87fe7a66459),
43 (0xb744fcd51fcb7640, 0x3aa430912f9fb79d),
44 ];
45
46 let mut r = DoubleDouble::quick_mul_f64_add(
47 DoubleDouble::from_bit_pair(C[5]),
48 z,
49 DoubleDouble::from_bit_pair(C[4]),
50 );
51 r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[3]));
52 r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[2]));
53 r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[1]));
54 DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[0]))
55}
56
57#[cold]
58fn exp2_accurate(x: f64) -> f64 {
59 let mut ix = x.to_bits();
60 let sx = 4096.0 * x;
61 let fx = sx.round_ties_even_finite();
62 let z = sx - fx;
63 let k: i64 = unsafe {
64 fx.to_int_unchecked::<i64>() };
66 let i1 = k & 0x3f;
67 let i0 = (k >> 6) & 0x3f;
68 let ie = k >> 12;
69
70 let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]);
71 let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]);
72 let dt = DoubleDouble::quick_mult(t0, t1);
73
74 let mut f = exp2_poly_dd(z);
75 f = DoubleDouble::quick_mult_f64(f, z);
76 if ix <= 0xc08ff00000000000u64 {
77 if f64::from_bits(0xbc971547652b82fe) <= x && x <= f64::from_bits(0x3ca71547652b82fd) {
81 return dd_fmla(x, 0.5, 1.0);
82 } else if (k & 0xfff) == 0 {
83 let zf = DoubleDouble::from_exact_add(dt.hi, f.hi);
85 let zfl = DoubleDouble::from_exact_add(zf.lo, f.lo);
86 f.hi = zf.hi;
87 f.lo = zfl.hi;
88 ix = zfl.hi.to_bits();
89 if ix & 0x000fffffffffffff == 0 {
90 if ((ix >> 52) & 0x7ff) != 0 {
92 let v = zfl.lo.to_bits();
94 let d: i64 = ((((ix as i64) >> 63) ^ ((v as i64) >> 63)) as u64)
95 .wrapping_shl(1)
96 .wrapping_add(1) as i64;
97 ix = ix.wrapping_add(d as u64);
98 f.lo = f64::from_bits(ix);
99 }
100 }
101 } else {
102 f = DoubleDouble::quick_mult(f, dt);
103 f = DoubleDouble::add(dt, f);
104 }
105 let hf = DoubleDouble::from_exact_add(f.hi, f.lo);
106
107 fast_ldexp(hf.hi, ie as i32)
108 } else {
109 ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52);
110 f = DoubleDouble::quick_mult(f, dt);
111 f = DoubleDouble::add(dt, f);
112 let zve = DoubleDouble::from_exact_add(f64::from_bits(ix), f.hi);
113 f.hi = zve.hi;
114 f.lo += zve.lo;
115
116 to_denormal(f.to_f64())
117 }
118}
119
120pub fn f_exp2(x: f64) -> f64 {
124 let mut ix = x.to_bits();
125 let ax = ix.wrapping_shl(1);
126 if ax == 0 {
127 return 1.0;
128 }
129 if ax >= 0x8120000000000000u64 {
130 if ax > 0xffe0000000000000u64 {
132 return x + x; }
134 if ax == 0xffe0000000000000u64 {
135 return if (ix >> 63) != 0 { 0.0 } else { x };
136 }
137 if (ix >> 63) != 0 {
139 if ix >= 0xc090cc0000000000u64 {
141 const Z: f64 = f64::from_bits(0x0010000000000000);
143 return Z * Z;
144 }
145 } else {
146 return f64::from_bits(0x7fe0000000000000) * x;
148 }
149 }
150
151 if ax <= 0x792e2a8eca5705fcu64 {
154 return 1.0 + f64::copysign(f64::from_bits(0x3c90000000000000), x);
155 }
156
157 let m = ix.wrapping_shl(12);
158 let ex = (ax >> 53).wrapping_sub(0x3ff);
159 let frac = ex >> 63 | m << (ex & 63);
160 let sx = 4096.0 * x;
161 let fx = sx.round_ties_even_finite();
162 let z = sx - fx;
163 let z2 = z * z;
164 let k = unsafe {
165 fx.to_int_unchecked::<i64>() };
167 let i1 = k & 0x3f;
168 let i0 = (k >> 6) & 0x3f;
169 let ie = k >> 12;
170 let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]);
171 let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]);
172 let ti0 = DoubleDouble::quick_mult(t0, t1);
173 const C: [u64; 4] = [
174 0x3f262e42fefa39ef,
175 0x3e4ebfbdff82c58f,
176 0x3d6c6b08d73b3e01,
177 0x3c83b2ab6fdda001,
178 ];
179 let tz = ti0.hi * z;
180 let mut fh = ti0.hi;
181
182 let p0 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0]));
183 let p1 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2]));
184 let p2 = f_fmla(z2, p1, p0);
185
186 let mut fl = f_fmla(tz, p2, ti0.lo);
187
188 const EPS: f64 = f64::from_bits(0x3c0833beace2b6fe);
189
190 if ix <= 0xc08ff00000000000u64 {
191 if frac != 0 {
193 let ub = fh + (fl + EPS);
194 fh += fl - EPS;
195 if ub != fh {
196 return exp2_accurate(x);
197 }
198 }
199 fh = fast_ldexp(fh, ie as i32);
200 } else {
201 ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52);
203 let rs = DoubleDouble::from_exact_add(f64::from_bits(ix), fh);
204 fl += rs.lo;
205 fh = rs.hi;
206 if frac != 0 {
207 let ub = fh + (fl + EPS);
208 fh += fl - EPS;
209 if ub != fh {
210 return exp2_accurate(x);
211 }
212 }
213 fh = to_denormal(fh);
215 }
216 fh
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_exp2d() {
225 assert_eq!(f_exp2(2.0), 4.0);
226 assert_eq!(f_exp2(3.0), 8.0);
227 assert_eq!(f_exp2(4.0), 16.0);
228 assert_eq!(f_exp2(0.35f64), 1.2745606273192622);
229 assert_eq!(f_exp2(-0.6f64), 0.6597539553864471);
230 assert_eq!(f_exp2(f64::INFINITY), f64::INFINITY);
231 assert_eq!(f_exp2(f64::NEG_INFINITY), 0.);
232 assert!(f_exp2(f64::NAN).is_nan());
233 }
234}