1const EXP_TABLE_BITS: u32 = 7;
11const EXP_N: u64 = 1 << EXP_TABLE_BITS;
12
13const EXP_INVLN2N: f64 = asdouble(0x40671547652B82FE);
14const EXP_NEGLN2HI_N: f64 = asdouble(0xBF762E42FEFA0000);
15const EXP_NEGLN2LO_N: f64 = asdouble(0xBD0CF79ABC9E3B3A);
16const EXP_SHIFT: f64 = asdouble(0x4338000000000000);
17
18const EXP_C2: f64 = asdouble(0x3FDFFFFFFFFFFDBD);
19const EXP_C3: f64 = asdouble(0x3FC555555555543C);
20const EXP_C4: f64 = asdouble(0x3FA55555CF172B91);
21const EXP_C5: f64 = asdouble(0x3F81111167A4D017);
22
23const EXP_1P1009: f64 = asdouble(0x7F00000000000000);
24const EXP_1P_NEG1022: f64 = asdouble(0x0010000000000000);
25
26const EXP_TAB: [u64; 256] = [
29 0x0, 0x3ff0000000000000,
30 0x3c9b3b4f1a88bf6e, 0x3feff63da9fb3335,
31 0xbc7160139cd8dc5d, 0x3fefec9a3e778061,
32 0xbc905e7a108766d1, 0x3fefe315e86e7f85,
33 0x3c8cd2523567f613, 0x3fefd9b0d3158574,
34 0xbc8bce8023f98efa, 0x3fefd06b29ddf6de,
35 0x3c60f74e61e6c861, 0x3fefc74518759bc8,
36 0x3c90a3e45b33d399, 0x3fefbe3ecac6f383,
37 0x3c979aa65d837b6d, 0x3fefb5586cf9890f,
38 0x3c8eb51a92fdeffc, 0x3fefac922b7247f7,
39 0x3c3ebe3d702f9cd1, 0x3fefa3ec32d3d1a2,
40 0xbc6a033489906e0b, 0x3fef9b66affed31b,
41 0xbc9556522a2fbd0e, 0x3fef9301d0125b51,
42 0xbc5080ef8c4eea55, 0x3fef8abdc06c31cc,
43 0xbc91c923b9d5f416, 0x3fef829aaea92de0,
44 0x3c80d3e3e95c55af, 0x3fef7a98c8a58e51,
45 0xbc801b15eaa59348, 0x3fef72b83c7d517b,
46 0xbc8f1ff055de323d, 0x3fef6af9388c8dea,
47 0x3c8b898c3f1353bf, 0x3fef635beb6fcb75,
48 0xbc96d99c7611eb26, 0x3fef5be084045cd4,
49 0x3c9aecf73e3a2f60, 0x3fef54873168b9aa,
50 0xbc8fe782cb86389d, 0x3fef4d5022fcd91d,
51 0x3c8a6f4144a6c38d, 0x3fef463b88628cd6,
52 0x3c807a05b0e4047d, 0x3fef3f49917ddc96,
53 0x3c968efde3a8a894, 0x3fef387a6e756238,
54 0x3c875e18f274487d, 0x3fef31ce4fb2a63f,
55 0x3c80472b981fe7f2, 0x3fef2b4565e27cdd,
56 0xbc96b87b3f71085e, 0x3fef24dfe1f56381,
57 0x3c82f7e16d09ab31, 0x3fef1e9df51fdee1,
58 0xbc3d219b1a6fbffa, 0x3fef187fd0dad990,
59 0x3c8b3782720c0ab4, 0x3fef1285a6e4030b,
60 0x3c6e149289cecb8f, 0x3fef0cafa93e2f56,
61 0x3c834d754db0abb6, 0x3fef06fe0a31b715,
62 0x3c864201e2ac744c, 0x3fef0170fc4cd831,
63 0x3c8fdd395dd3f84a, 0x3feefc08b26416ff,
64 0xbc86a3803b8e5b04, 0x3feef6c55f929ff1,
65 0xbc924aedcc4b5068, 0x3feef1a7373aa9cb,
66 0xbc9907f81b512d8e, 0x3feeecae6d05d866,
67 0xbc71d1e83e9436d2, 0x3feee7db34e59ff7,
68 0xbc991919b3ce1b15, 0x3feee32dc313a8e5,
69 0x3c859f48a72a4c6d, 0x3feedea64c123422,
70 0xbc9312607a28698a, 0x3feeda4504ac801c,
71 0xbc58a78f4817895b, 0x3feed60a21f72e2a,
72 0xbc7c2c9b67499a1b, 0x3feed1f5d950a897,
73 0x3c4363ed60c2ac11, 0x3feece086061892d,
74 0x3c9666093b0664ef, 0x3feeca41ed1d0057,
75 0x3c6ecce1daa10379, 0x3feec6a2b5c13cd0,
76 0x3c93ff8e3f0f1230, 0x3feec32af0d7d3de,
77 0x3c7690cebb7aafb0, 0x3feebfdad5362a27,
78 0x3c931dbdeb54e077, 0x3feebcb299fddd0d,
79 0xbc8f94340071a38e, 0x3feeb9b2769d2ca7,
80 0xbc87deccdc93a349, 0x3feeb6daa2cf6642,
81 0xbc78dec6bd0f385f, 0x3feeb42b569d4f82,
82 0xbc861246ec7b5cf6, 0x3feeb1a4ca5d920f,
83 0x3c93350518fdd78e, 0x3feeaf4736b527da,
84 0x3c7b98b72f8a9b05, 0x3feead12d497c7fd,
85 0x3c9063e1e21c5409, 0x3feeab07dd485429,
86 0x3c34c7855019c6ea, 0x3feea9268a5946b7,
87 0x3c9432e62b64c035, 0x3feea76f15ad2148,
88 0xbc8ce44a6199769f, 0x3feea5e1b976dc09,
89 0xbc8c33c53bef4da8, 0x3feea47eb03a5585,
90 0xbc845378892be9ae, 0x3feea34634ccc320,
91 0xbc93cedd78565858, 0x3feea23882552225,
92 0x3c5710aa807e1964, 0x3feea155d44ca973,
93 0xbc93b3efbf5e2228, 0x3feea09e667f3bcd,
94 0xbc6a12ad8734b982, 0x3feea012750bdabf,
95 0xbc6367efb86da9ee, 0x3fee9fb23c651a2f,
96 0xbc80dc3d54e08851, 0x3fee9f7df9519484,
97 0xbc781f647e5a3ecf, 0x3fee9f75e8ec5f74,
98 0xbc86ee4ac08b7db0, 0x3fee9f9a48a58174,
99 0xbc8619321e55e68a, 0x3fee9feb564267c9,
100 0x3c909ccb5e09d4d3, 0x3feea0694fde5d3f,
101 0xbc7b32dcb94da51d, 0x3feea11473eb0187,
102 0x3c94ecfd5467c06b, 0x3feea1ed0130c132,
103 0x3c65ebe1abd66c55, 0x3feea2f336cf4e62,
104 0xbc88a1c52fb3cf42, 0x3feea427543e1a12,
105 0xbc9369b6f13b3734, 0x3feea589994cce13,
106 0xbc805e843a19ff1e, 0x3feea71a4623c7ad,
107 0xbc94d450d872576e, 0x3feea8d99b4492ed,
108 0x3c90ad675b0e8a00, 0x3feeaac7d98a6699,
109 0x3c8db72fc1f0eab4, 0x3feeace5422aa0db,
110 0xbc65b6609cc5e7ff, 0x3feeaf3216b5448c,
111 0x3c7bf68359f35f44, 0x3feeb1ae99157736,
112 0xbc93091fa71e3d83, 0x3feeb45b0b91ffc6,
113 0xbc5da9b88b6c1e29, 0x3feeb737b0cdc5e5,
114 0xbc6c23f97c90b959, 0x3feeba44cbc8520f,
115 0xbc92434322f4f9aa, 0x3feebd829fde4e50,
116 0xbc85ca6cd7668e4b, 0x3feec0f170ca07ba,
117 0x3c71affc2b91ce27, 0x3feec49182a3f090,
118 0x3c6dd235e10a73bb, 0x3feec86319e32323,
119 0xbc87c50422622263, 0x3feecc667b5de565,
120 0x3c8b1c86e3e231d5, 0x3feed09bec4a2d33,
121 0xbc91bbd1d3bcbb15, 0x3feed503b23e255d,
122 0x3c90cc319cee31d2, 0x3feed99e1330b358,
123 0x3c8469846e735ab3, 0x3feede6b5579fdbf,
124 0xbc82dfcd978e9db4, 0x3feee36bbfd3f37a,
125 0x3c8c1a7792cb3387, 0x3feee89f995ad3ad,
126 0xbc907b8f4ad1d9fa, 0x3feeee07298db666,
127 0xbc55c3d956dcaeba, 0x3feef3a2b84f15fb,
128 0xbc90a40e3da6f640, 0x3feef9728de5593a,
129 0xbc68d6f438ad9334, 0x3feeff76f2fb5e47,
130 0xbc91eee26b588a35, 0x3fef05b030a1064a,
131 0x3c74ffd70a5fddcd, 0x3fef0c1e904bc1d2,
132 0xbc91bdfbfa9298ac, 0x3fef12c25bd71e09,
133 0x3c736eae30af0cb3, 0x3fef199bdd85529c,
134 0x3c8ee3325c9ffd94, 0x3fef20ab5fffd07a,
135 0x3c84e08fd10959ac, 0x3fef27f12e57d14b,
136 0x3c63cdaf384e1a67, 0x3fef2f6d9406e7b5,
137 0x3c676b2c6c921968, 0x3fef3720dcef9069,
138 0xbc808a1883ccb5d2, 0x3fef3f0b555dc3fa,
139 0xbc8fad5d3ffffa6f, 0x3fef472d4a07897c,
140 0xbc900dae3875a949, 0x3fef4f87080d89f2,
141 0x3c74a385a63d07a7, 0x3fef5818dcfba487,
142 0xbc82919e2040220f, 0x3fef60e316c98398,
143 0x3c8e5a50d5c192ac, 0x3fef69e603db3285,
144 0x3c843a59ac016b4b, 0x3fef7321f301b460,
145 0xbc82d52107b43e1f, 0x3fef7c97337b9b5f,
146 0xbc892ab93b470dc9, 0x3fef864614f5a129,
147 0x3c74b604603a88d3, 0x3fef902ee78b3ff6,
148 0x3c83c5ec519d7271, 0x3fef9a51fbc74c83,
149 0xbc8ff7128fd391f0, 0x3fefa4afa2a490da,
150 0xbc8dae98e223747d, 0x3fefaf482d8e67f1,
151 0x3c8ec3bc41aa2008, 0x3fefba1bee615a27,
152 0x3c842b94c3a9eb32, 0x3fefc52b376bba97,
153 0x3c8a64a931d185ee, 0x3fefd0765b6e4540,
154 0xbc8e37bae43be3ed, 0x3fefdbfdad9cbe14,
155 0x3c77893b4d91cd9d, 0x3fefe7c1819e90d8,
156 0x3c5305c14160cc89, 0x3feff3c22b8f71f1,
157];
158
159const EXP2F_TABLE_BITS: u32 = 5;
164const EXP2F_N: u64 = 1 << EXP2F_TABLE_BITS;
165
166const EXP2F_SHIFT_SCALED: f64 = asdouble(0x42E8000000000000);
167const EXP2F_POLY: [f64; 3] = [
168 asdouble(0x3FAC6AF84B912394),
169 asdouble(0x3FCEBFCE50FAC4F3),
170 asdouble(0x3FE62E42FF0C52D6),
171];
172const EXP2F_SHIFT: f64 = asdouble(0x4338000000000000);
173const EXP2F_INVLN2_SCALED: f64 = asdouble(0x40471547652B82FE);
174const EXP2F_POLY_SCALED: [f64; 3] = [
175 asdouble(0x3EBC6AF84B912394),
176 asdouble(0x3F2EBFCE50FAC4F3),
177 asdouble(0x3F962E42FF0C52D6),
178];
179
180const EXP2F_TAB: [u64; 32] = [
182 0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51,
183 0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1,
184 0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d,
185 0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585,
186 0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13,
187 0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d,
188 0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069,
189 0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540,
190];
191
192const EXP2F_OVFL: f32 = asfloat(0x42B17217);
193const EXP2F_UVFL: f32 = asfloat(0xC2CFF1B4);
194
195#[inline]
200fn exp_top12(x: f64) -> u32 {
201 (asuint64(x) >> 52) as u32
202}
203
204#[inline]
205fn exp_specialcase(tmp: f64, sbits: u64, ki: u64) -> f64 {
206 if (ki & 0x80000000) == 0 {
207 let sbits = sbits.wrapping_sub(1009u64 << 52);
209 let scale = asdouble(sbits);
210 let y = EXP_1P1009 * (scale + scale * tmp);
211 return eval_as_double(y);
212 }
213 let sbits = sbits + (1022u64 << 52);
215 let scale = asdouble(sbits);
216 let mut y = scale + scale * tmp;
217 if y < 1.0 {
218 let lo = scale - y + scale * tmp;
219 let hi = 1.0 + y;
220 let lo = 1.0 - hi + y + lo;
221 y = eval_as_double(hi + lo) - 1.0;
222 if y == 0.0 {
223 y = 0.0; }
225 fp_force_eval(fp_barrier(EXP_1P_NEG1022) * EXP_1P_NEG1022);
227 }
228 y = EXP_1P_NEG1022 * y;
229 eval_as_double(y)
230}
231
232#[no_mangle]
233pub extern "C" fn exp(x: f64) -> f64 {
234 let mut abstop = exp_top12(x) & 0x7ff;
235
236 if predict_false(abstop.wrapping_sub(0x3C9) >= 0x408 - 0x3C9) {
237 if abstop.wrapping_sub(0x3C9) >= 0x80000000 {
238 return 1.0 + x;
240 }
241 if abstop >= 0x409 {
242 if x == f64::NEG_INFINITY {
243 return 0.0;
244 }
245 if abstop >= 0x7FF {
246 return 1.0 + x; }
248 if asuint64(x) >> 63 != 0 {
249 return __math_uflow(0);
250 } else {
251 return __math_oflow(0);
252 }
253 }
254 abstop = 0;
256 }
257
258 let z = EXP_INVLN2N * x;
259 let kd = eval_as_double(z + EXP_SHIFT);
260 let ki = asuint64(kd);
261 let kd = kd - EXP_SHIFT;
262 let r = x + kd * EXP_NEGLN2HI_N + kd * EXP_NEGLN2LO_N;
263 let idx = (2 * (ki % EXP_N)) as usize;
264 let top = ki << (52 - EXP_TABLE_BITS);
265 let tail = asdouble(EXP_TAB[idx]);
266 let sbits = EXP_TAB[idx + 1].wrapping_add(top);
267 let r2 = r * r;
268 let tmp = tail + r + r2 * (EXP_C2 + r * EXP_C3) + r2 * r2 * (EXP_C4 + r * EXP_C5);
269
270 if predict_false(abstop == 0) {
271 return exp_specialcase(tmp, sbits, ki);
272 }
273 let scale = asdouble(sbits);
274 eval_as_double(scale + scale * tmp)
275}
276
277const EXP2_SHIFT: f64 = asdouble(0x42C8000000000000);
282const EXP2_1P_NEG54: f64 = asdouble(0x3C90000000000000);
283const EXP2_C1: f64 = asdouble(0x3FE62E42FEFA39EF);
284const EXP2_C2: f64 = asdouble(0x3FCEBFBDFF82C424);
285const EXP2_C3: f64 = asdouble(0x3FAC6B08D70CF4B5);
286const EXP2_C4: f64 = asdouble(0x3F83B2ABD24650CC);
287const EXP2_C5: f64 = asdouble(0x3F55D7E09B4E3A84);
288
289#[inline]
290fn exp2_specialcase(tmp: f64, sbits: u64, ki: u64) -> f64 {
291 if (ki & 0x80000000) == 0 {
292 let sbits = sbits.wrapping_sub(1u64 << 52);
294 let scale = asdouble(sbits);
295 let y = 2.0 * (scale + scale * tmp);
296 return eval_as_double(y);
297 }
298 let sbits = sbits.wrapping_add(1022u64 << 52);
300 let scale = asdouble(sbits);
301 let mut y = scale + scale * tmp;
302 if y < 1.0 {
303 let lo = scale - y + scale * tmp;
304 let hi = 1.0 + y;
305 let lo = 1.0 - hi + y + lo;
306 y = eval_as_double(hi + lo) - 1.0;
307 if y == 0.0 {
309 y = 0.0;
310 }
311 fp_force_eval(fp_barrier(EXP_1P_NEG1022) * EXP_1P_NEG1022);
313 }
314 y = EXP_1P_NEG1022 * y;
315 eval_as_double(y)
316}
317
318pub(crate) fn exp2_impl(x: f64) -> f64 {
319 let top12 = |v: f64| (asuint64(v) >> 52) as u32;
320 let mut abstop = top12(x) & 0x7ff;
321 if predict_false(abstop.wrapping_sub(top12(EXP2_1P_NEG54)) >= top12(512.0) - top12(EXP2_1P_NEG54)) {
322 if abstop.wrapping_sub(top12(EXP2_1P_NEG54)) >= 0x80000000 {
323 return 1.0 + x;
325 }
326 if abstop >= top12(1024.0) {
327 if asuint64(x) == asuint64(f64::NEG_INFINITY) {
328 return 0.0;
329 }
330 if abstop >= top12(f64::INFINITY) {
331 return 1.0 + x;
332 }
333 if asuint64(x) >> 63 == 0 {
334 return __math_oflow(0);
335 } else if asuint64(x) >= asuint64(-1075.0) {
336 return __math_uflow(0);
337 }
338 }
339 if 2u64.wrapping_mul(asuint64(x)) > 2u64.wrapping_mul(asuint64(928.0)) {
340 abstop = 0;
342 }
343 }
344
345 let kd = eval_as_double(x + EXP2_SHIFT);
347 let ki = asuint64(kd);
348 let kd = kd - EXP2_SHIFT;
349 let r = x - kd;
350 let idx = (2 * (ki % EXP_N)) as usize;
351 let top = ki << (52 - EXP_TABLE_BITS);
352 let tail = asdouble(EXP_TAB[idx]);
353 let sbits = EXP_TAB[idx + 1].wrapping_add(top);
354 let r2 = r * r;
355 let tmp = tail
356 + r * EXP2_C1
357 + r2 * (EXP2_C2 + r * EXP2_C3)
358 + r2 * r2 * (EXP2_C4 + r * EXP2_C5);
359 if predict_false(abstop == 0) {
360 return exp2_specialcase(tmp, sbits, ki);
361 }
362 let scale = asdouble(sbits);
363 eval_as_double(scale + scale * tmp)
364}
365
366#[inline]
371fn expf_top12(x: f32) -> u32 {
372 asuint(x) >> 20
373}
374
375#[no_mangle]
376pub extern "C" fn expf(x: f32) -> f32 {
377 let xd = x as f64;
378 let abstop = expf_top12(x) & 0x7ff;
379
380 if predict_false(abstop >= 0x42B) {
381 if x == f32::NEG_INFINITY {
382 return 0.0;
383 }
384 if abstop >= 0x7F8 {
385 return x + x; }
387 if x > EXP2F_OVFL {
388 return __math_oflowf(0);
389 }
390 if x < EXP2F_UVFL {
391 return __math_uflowf(0);
392 }
393 }
394
395 let z = EXP2F_INVLN2_SCALED * xd;
396 let kd = eval_as_double(z + EXP2F_SHIFT);
397 let ki = asuint64(kd);
398 let kd = kd - EXP2F_SHIFT;
399 let r = z - kd;
400
401 let t = EXP2F_TAB[(ki % EXP2F_N) as usize].wrapping_add(ki << (52 - EXP2F_TABLE_BITS));
402 let s = asdouble(t);
403 let z = EXP2F_POLY_SCALED[0] * r + EXP2F_POLY_SCALED[1];
404 let r2 = r * r;
405 let mut y = EXP2F_POLY_SCALED[2] * r + 1.0;
406 y = z * r2 + y;
407 y = y * s;
408 y as f32
409}