1use crate::common::{dd_fmla, dyad_fmla, f_fmla};
30use crate::double_double::DoubleDouble;
31use crate::exponents::exp2m1::{EXP_M1_2_TABLE1, EXP_M1_2_TABLE2};
32use crate::floor::FloorFinite;
33use crate::round_ties_even::RoundTiesEven;
34
35const LN10H: f64 = f64::from_bits(0x40026bb1bbb55516);
36const LN10L: f64 = f64::from_bits(0xbcaf48ad494ea3e9);
37
38struct Exp10m1 {
39 exp: DoubleDouble,
40 err: f64,
41}
42
43#[inline]
47fn q_1(dz: DoubleDouble) -> DoubleDouble {
48 const Q_1: [u64; 5] = [
49 0x3ff0000000000000,
50 0x3ff0000000000000,
51 0x3fe0000000000000,
52 0x3fc5555555995d37,
53 0x3fa55555558489dc,
54 ];
55 let z = dz.to_f64();
56 let mut q = f_fmla(f64::from_bits(Q_1[4]), dz.hi, f64::from_bits(Q_1[3]));
57 q = f_fmla(q, z, f64::from_bits(Q_1[2]));
58
59 let mut p0 = DoubleDouble::from_exact_add(f64::from_bits(Q_1[1]), q * z);
60 p0 = DoubleDouble::quick_mult(dz, p0);
61 p0 = DoubleDouble::f64_add(f64::from_bits(Q_1[0]), p0);
62 p0
63}
64
65#[inline]
66fn exp1(x: DoubleDouble) -> DoubleDouble {
67 const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (x.hi * INVLOG2).round_ties_even_finite();
69
70 const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef);
71 const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f);
72 let mut zk = DoubleDouble::from_exact_mult(LOG2H, k);
73 zk.lo = f_fmla(k, LOG2L, zk.lo);
74
75 let mut yz = DoubleDouble::from_exact_add(x.hi - zk.hi, x.lo);
76 yz.lo -= zk.lo;
77
78 let ik: i64 = unsafe { k.to_int_unchecked::<i64>() }; let im: i64 = (ik >> 12).wrapping_add(0x3ff);
80 let i2: i64 = (ik >> 6) & 0x3f;
81 let i1: i64 = ik & 0x3f;
82
83 let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]);
84 let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]);
85
86 let p0 = DoubleDouble::quick_mult(t2, t1);
87
88 let mut q = q_1(yz);
89 q = DoubleDouble::quick_mult(p0, q);
90
91 let mut du = (im as u64).wrapping_shl(52);
94 if im == 0x7ff {
95 q.hi *= 2.0;
96 q.lo *= 2.0;
97 du = (im.wrapping_sub(1) as u64).wrapping_shl(52);
98 }
99 q.hi *= f64::from_bits(du);
100 q.lo *= f64::from_bits(du);
101 q
102}
103
104#[inline]
105fn exp10m1_fast(x: f64, tiny: bool) -> Exp10m1 {
106 if tiny {
107 return exp10m1_fast_tiny(x);
108 }
109 let v = DoubleDouble::quick_mult_f64(DoubleDouble::new(LN10L, LN10H), x);
112 let mut p = exp1(v);
124
125 let zf: DoubleDouble = if x >= 0. {
126 DoubleDouble::from_exact_add(p.hi, -1.0)
128 } else {
129 DoubleDouble::from_exact_add(-1.0, p.hi)
130 };
131 p.lo += zf.lo;
132 p.hi = zf.hi;
133 Exp10m1 {
140 exp: p,
141 err: f64::from_bits(0x3b77a00000000000) * p.hi, }
143}
144
145#[inline]
149fn q_2(dz: DoubleDouble) -> DoubleDouble {
150 const Q_2: [u64; 9] = [
164 0x3ff0000000000000,
165 0x3ff0000000000000,
166 0x3fe0000000000000,
167 0x3fc5555555555555,
168 0x3c655555555c4d26,
169 0x3fa5555555555555,
170 0x3f81111111111111,
171 0x3f56c16c3fbb4213,
172 0x3f2a01a023ede0d7,
173 ];
174
175 let z = dz.to_f64();
176 let mut q = dd_fmla(f64::from_bits(Q_2[8]), dz.hi, f64::from_bits(Q_2[7]));
177 q = dd_fmla(q, z, f64::from_bits(Q_2[6]));
178 q = dd_fmla(q, z, f64::from_bits(Q_2[5]));
179
180 let mut p = DoubleDouble::from_exact_mult(q, z);
183 let r0 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[3]), p.hi);
184 p.hi = r0.hi;
185 p.lo += r0.lo + f64::from_bits(Q_2[4]);
186
187 p = DoubleDouble::quick_mult(p, dz);
190 let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[2]), p.hi);
191 p.hi = r1.hi;
192 p.lo += r1.lo;
193
194 p = DoubleDouble::quick_mult(p, dz);
196 let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[1]), p.hi);
197 p.hi = r1.hi;
198 p.lo += r1.lo;
199
200 p = DoubleDouble::quick_mult(p, dz);
202 let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[0]), p.hi);
203 p.hi = r1.hi;
204 p.lo += r1.lo;
205 p
206}
207
208#[inline]
211fn exp_2(x: f64) -> DoubleDouble {
212 let mut k = (x * f64::from_bits(0x40ca934f0979a371)).round_ties_even_finite();
213 if k == 4194304. {
214 k = 4194303.; }
216 const LOG2_10H: f64 = f64::from_bits(0x3f134413509f79ff);
219 const LOG2_10M: f64 = f64::from_bits(0xbb89dc1da9800000);
220 const LOG2_10L: f64 = f64::from_bits(0xb984fd20dba1f655);
221
222 let yhh = dd_fmla(-k, LOG2_10H, x); let mut ky0 = DoubleDouble::from_exact_add(yhh, -k * LOG2_10M);
225 ky0.lo = dd_fmla(-k, LOG2_10L, ky0.lo);
226
227 let ky = DoubleDouble::quick_mult(ky0, DoubleDouble::new(LN10L, LN10H));
231
232 let ik = unsafe {
233 k.to_int_unchecked::<i64>() };
235 let im = (ik >> 12).wrapping_add(0x3ff);
236 let i2 = (ik >> 6) & 0x3f;
237 let i1 = ik & 0x3f;
238
239 let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]);
240 let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]);
241
242 let p = DoubleDouble::quick_mult(t2, t1);
243
244 let mut q = q_2(ky);
245 q = DoubleDouble::quick_mult(p, q);
246 let mut ud: u64 = (im as u64).wrapping_shl(52);
247
248 if im == 0x7ff {
249 q.hi *= 2.0;
250 q.lo *= 2.0;
251 ud = (im.wrapping_sub(1) as u64).wrapping_shl(52);
252 }
253 q.hi *= f64::from_bits(ud);
254 q.lo *= f64::from_bits(ud);
255 q
256}
257
258#[cold]
259fn exp10m1_accurate_tiny(x: f64) -> f64 {
260 let x2 = x * x;
261 let x4 = x2 * x2;
262 const Q: [u64; 25] = [
268 0x40026bb1bbb55516,
269 0xbcaf48ad494ea3e9,
270 0x40053524c73cea69,
271 0xbcae2bfab318d696,
272 0x4000470591de2ca4,
273 0x3ca823527cebf918,
274 0x3ff2bd7609fd98c4,
275 0x3c931ea51f6641df,
276 0x3fe1429ffd1d4d76,
277 0x3c7117195be7f232,
278 0x3fca7ed70847c8b6,
279 0xbc54260c5e23d0c8,
280 0x3fb16e4dfc333a87,
281 0xbc533fd284110905,
282 0x3f94116b05fdaa5d,
283 0xbc20721de44d79a8,
284 0x3f74897c45d93d43,
285 0x3f52ea52b2d182ac,
286 0x3f2facfd5d905b22,
287 0x3f084fe12df8bde3,
288 0x3ee1398ad75d01bf,
289 0x3eb6a9e96fbf6be7,
290 0x3e8bd456a29007c2,
291 0x3e6006cf8378cf9b,
292 0x3e368862b132b6e2,
293 ];
294 let mut c13 = dd_fmla(f64::from_bits(Q[23]), x, f64::from_bits(Q[22])); let c11 = dd_fmla(f64::from_bits(Q[21]), x, f64::from_bits(Q[20])); c13 = dd_fmla(f64::from_bits(Q[24]), x2, c13); let mut p = DoubleDouble::from_exact_add(
299 f64::from_bits(Q[18]),
300 f_fmla(f64::from_bits(Q[19]), x, f_fmla(c11, x2, c13 * x4)),
301 );
302 p = DoubleDouble::quick_f64_mult(x, p);
304 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[17]), p.hi);
305 p.lo += p0.lo;
306 p.hi = p0.hi;
307
308 p = DoubleDouble::quick_f64_mult(x, p);
310 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[16]), p.hi);
311 p.lo += p0.lo;
312 p.hi = p0.hi;
313 p = DoubleDouble::quick_f64_mult(x, p);
315 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[14]), p.hi);
316 p.lo += p0.lo + f64::from_bits(Q[15]);
317 p.hi = p0.hi;
318 p = DoubleDouble::quick_f64_mult(x, p);
320 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[12]), p.hi);
321 p.lo += p0.lo + f64::from_bits(Q[13]);
322 p.hi = p0.hi;
323
324 p = DoubleDouble::quick_f64_mult(x, p);
326 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[10]), p.hi);
327 p.lo += p0.lo + f64::from_bits(Q[11]);
328 p.hi = p0.hi;
329
330 p = DoubleDouble::quick_f64_mult(x, p);
332 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[8]), p.hi);
333 p.lo += p0.lo + f64::from_bits(Q[9]);
334 p.hi = p0.hi;
335
336 p = DoubleDouble::quick_f64_mult(x, p);
338 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[6]), p.hi);
339 p.lo += p0.lo + f64::from_bits(Q[7]);
340 p.hi = p0.hi;
341
342 p = DoubleDouble::quick_f64_mult(x, p);
344 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[4]), p.hi);
345 p.lo += p0.lo + f64::from_bits(Q[5]);
346 p.hi = p0.hi;
347
348 p = DoubleDouble::quick_f64_mult(x, p);
350 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[2]), p.hi);
351 p.lo += p0.lo + f64::from_bits(Q[3]);
352 p.hi = p0.hi;
353
354 p = DoubleDouble::quick_f64_mult(x, p);
356 let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[0]), p.hi);
357 p.lo += p0.lo + f64::from_bits(Q[1]);
358 p.hi = p0.hi;
359
360 p = DoubleDouble::quick_f64_mult(x, p);
362 p.to_f64()
363}
364
365#[cold]
366fn exp10m1_accurate(x: f64) -> f64 {
367 let t = x.to_bits();
368 let ux = t;
369 let ax = ux & 0x7fffffffffffffffu64;
370
371 if ax <= 0x3fc0000000000000u64 {
372 return exp10m1_accurate_tiny(x);
374 }
375
376 let mut p = exp_2(x);
377
378 let zf: DoubleDouble = DoubleDouble::from_full_exact_add(p.hi, -1.0);
379 p.lo += zf.lo;
380 p.hi = zf.hi;
381 p.to_f64()
382}
383
384#[inline]
394fn exp10m1_fast_tiny(x: f64) -> Exp10m1 {
395 const P: [u64; 14] = [
400 0x40026bb1bbb55516,
401 0xbcaf48abcf79e094,
402 0x40053524c73cea69,
403 0xbcae1badf796d704,
404 0x4000470591de2ca4,
405 0x3ca7db8caacb2cea,
406 0x3ff2bd7609fd98ba,
407 0x3fe1429ffd1d4d98,
408 0x3fca7ed7084998e1,
409 0x3fb16e4dfc30944b,
410 0x3f94116ae4b57526,
411 0x3f74897c6a90f61c,
412 0x3f52ec689c32b3a0,
413 0x3f2faced20d698fe,
414 ];
415 let x2 = x * x;
416 let x4 = x2 * x2;
417 let mut c9 = dd_fmla(f64::from_bits(P[12]), x, f64::from_bits(P[11])); let c7 = dd_fmla(f64::from_bits(P[10]), x, f64::from_bits(P[9])); let mut c5 = dd_fmla(f64::from_bits(P[8]), x, f64::from_bits(P[7])); c9 = dd_fmla(f64::from_bits(P[13]), x2, c9); c5 = dd_fmla(c7, x2, c5); c5 = dd_fmla(c9, x4, c5); let mut p = DoubleDouble::from_exact_mult(c5, x);
425 let p0 = DoubleDouble::from_exact_add(f64::from_bits(P[6]), p.hi);
426 p.lo += p0.lo;
427 p.hi = p0.hi;
428
429 p = DoubleDouble::quick_f64_mult(x, p);
430
431 let p1 = DoubleDouble::from_exact_add(f64::from_bits(P[4]), p.hi);
432 p.lo += p1.lo + f64::from_bits(P[5]);
433 p.hi = p1.hi;
434
435 p = DoubleDouble::quick_f64_mult(x, p);
436
437 let p2 = DoubleDouble::from_exact_add(f64::from_bits(P[2]), p.hi);
438 p.lo += p2.lo + f64::from_bits(P[3]);
439 p.hi = p2.hi;
440
441 p = DoubleDouble::quick_f64_mult(x, p);
442
443 let p2 = DoubleDouble::from_exact_add(f64::from_bits(P[0]), p.hi);
444 p.lo += p2.lo + f64::from_bits(P[1]);
445 p.hi = p2.hi;
446
447 p = DoubleDouble::quick_f64_mult(x, p);
448
449 Exp10m1 {
450 exp: p,
451 err: f64::from_bits(0x3bb0a00000000000) * p.hi, }
453}
454
455pub fn f_exp10m1(d: f64) -> f64 {
459 let mut x = d;
460 let t = x.to_bits();
461 let ux = t;
462 let ax = ux & 0x7fffffffffffffffu64;
463
464 if ux >= 0xc03041704c068ef0u64 {
465 if (ux >> 52) == 0xfff {
467 return if ux > 0xfff0000000000000u64 {
469 x + x
470 } else {
471 -1.0
472 };
473 }
474 return -1.0 + f64::from_bits(0x3c90000000000000);
476 } else if ax > 0x40734413509f79feu64 {
477 if (ux >> 52) == 0x7ff {
479 return x + x;
481 }
482 return f64::from_bits(0x7fefffffffffffff) * x;
483 } else if ax <= 0x3c90000000000000u64
484 {
489 return if ax <= 0x3970000000000000u64
493 {
495 if x == 0. {
497 return x;
498 }
499 if x.abs() == f64::from_bits(0x000086c73059343c) {
500 return dd_fmla(
501 -f64::copysign(f64::from_bits(0x1e60010000000000), x),
502 f64::from_bits(0x1e50000000000000),
503 f64::copysign(f64::from_bits(0x000136568740cb56), x),
504 );
505 }
506 if x.abs() == f64::from_bits(0x00013a7b70d0248c) {
507 return dd_fmla(
508 f64::copysign(f64::from_bits(0x1e5ffe0000000000), x),
509 f64::from_bits(0x1e50000000000000),
510 f64::copysign(f64::from_bits(0x0002d41f3b972fc7), x),
511 );
512 }
513
514 x *= f64::from_bits(0x4690000000000000);
516 let mut z = DoubleDouble::from_exact_mult(LN10H, x);
517 z.lo = dd_fmla(LN10L, x, z.lo);
518 let mut h2 = z.to_f64(); h2 *= f64::from_bits(0x3950000000000000);
521 let mut h = dd_fmla(-h2, f64::from_bits(0x4690000000000000), z.hi);
523 h += z.lo;
525 dyad_fmla(h, f64::from_bits(0x3950000000000000), h2)
530 } else {
531 const C2: f64 = f64::from_bits(0x40053524c73cea69); let mut z = DoubleDouble::quick_mult_f64(DoubleDouble::new(LN10L, LN10H), x);
533 z.lo = dd_fmla(C2 * x, x, z.lo);
537 z.to_f64()
538 };
539 }
540
541 if ux << 15 == 0 {
546 let i = x.floor_finite() as i32;
547 if x == i as f64 && 1 <= i && i <= 15 {
548 static EXP10_1_15: [u64; 16] = [
549 0x0000000000000000,
550 0x4022000000000000,
551 0x4058c00000000000,
552 0x408f380000000000,
553 0x40c3878000000000,
554 0x40f869f000000000,
555 0x412e847e00000000,
556 0x416312cfe0000000,
557 0x4197d783fc000000,
558 0x41cdcd64ff800000,
559 0x4202a05f1ff80000,
560 0x42374876e7ff0000,
561 0x426d1a94a1ffe000,
562 0x42a2309ce53ffe00,
563 0x42d6bcc41e8fffc0,
564 0x430c6bf52633fff8,
565 ];
566 return f64::from_bits(EXP10_1_15[i as usize]);
567 }
568 }
569
570 let result = exp10m1_fast(x, ax <= 0x3fb0000000000000u64);
571 let left = result.exp.hi + (result.exp.lo - result.err);
572 let right = result.exp.hi + (result.exp.lo + result.err);
573 if left != right {
574 return exp10m1_accurate(x);
575 }
576 left
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582
583 #[test]
584 fn test_exp10m1() {
585 assert_eq!(f_exp10m1(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002364140972981833),
586 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005443635762124408);
587 assert_eq!(99., f_exp10m1(2.0));
588 assert_eq!(315.22776601683796, f_exp10m1(2.5));
589 assert_eq!(-0.7056827241416722, f_exp10m1(-0.5311842449009418));
590 }
591}