1use crate::bessel::bessel_exp::i0_exp_accurate;
30use crate::bessel::i0::{
31 bessel_rsqrt_hard, eval_small_hard_3p6_to_7p5, i0_0_to_3p6_dd, i0_0_to_3p6_hard,
32 i0_3p6_to_7p5_dd,
33};
34use crate::bessel::i0_exp;
35use crate::common::f_fmla;
36use crate::double_double::DoubleDouble;
37use crate::dyadic_float::{DyadicFloat128, DyadicSign};
38
39pub fn f_i0e(x: f64) -> f64 {
43 let ux = x.to_bits().wrapping_shl(1);
44
45 if ux >= 0x7ffu64 << 53 || ux <= 0x7960000000000000u64 {
46 if ux <= 0x760af31dc4611874u64 {
48 return 1.;
50 }
51 if ux <= 0x7960000000000000u64 {
52 return 1. - x;
55 }
56 if x.is_infinite() {
57 return 0.;
58 }
59 return x + f64::NAN; }
61
62 let xb = x.to_bits() & 0x7fff_ffff_ffff_ffff;
63
64 if xb <= 0x4023000000000000u64 {
65 if xb <= 0x400ccccccccccccdu64 {
67 return i0e_0_to_3p6_exec(f64::from_bits(xb));
69 } else if xb <= 0x401e000000000000u64 {
70 return i0e3p6_to_7p5(f64::from_bits(xb));
72 }
73 return i0e_7p5_to_9p5(f64::from_bits(xb));
74 }
75
76 i0e_asympt(f64::from_bits(xb))
77}
78
79#[inline]
83fn i0e3p6_to_7p5(x: f64) -> f64 {
84 let mut r = i0_3p6_to_7p5_dd(x);
85
86 let v_exp = i0_exp(-x);
87 r = DoubleDouble::quick_mult(r, v_exp);
88
89 let err = f_fmla(
90 r.hi,
91 f64::from_bits(0x3c56a09e667f3bcd), f64::from_bits(0x3c00000000000000), );
94 let ub = r.hi + (r.lo + err);
95 let lb = r.hi + (r.lo - err);
96 if ub == lb {
97 return ub;
98 }
99 let v = eval_small_hard_3p6_to_7p5(x);
100 let v_exp_accurate = i0_exp_accurate(-x);
101 DoubleDouble::quick_mult(v, v_exp_accurate).to_f64()
102}
103
104#[inline]
105fn i0e_0_to_3p6_exec(x: f64) -> f64 {
106 let mut r = i0_0_to_3p6_dd(x);
107
108 let v_exp = i0_exp(-x);
109 r = DoubleDouble::quick_mult(r, v_exp);
110
111 let err = f_fmla(
112 r.hi,
113 f64::from_bits(0x3c40000000000000), f64::from_bits(0x3be0000000000000), );
116 let ub = r.hi + (r.lo + err);
117 let lb = r.hi + (r.lo - err);
118 if ub == lb {
119 return ub;
120 }
121 let v = i0_0_to_3p6_hard(x);
122 let v_exp_accurate = i0_exp_accurate(-x);
123 DoubleDouble::quick_mult(v, v_exp_accurate).to_f64()
124}
125
126#[inline]
143fn i0e_7p5_to_9p5(x: f64) -> f64 {
144 let dx = x;
145 let recip = DoubleDouble::from_quick_recip(x);
146
147 const P: [(u64, u64); 12] = [
148 (0x3c778e3de1f76f48, 0x3fd988450531281b),
149 (0xbcb572f6149f389e, 0xc01a786676fb4d3a),
150 (0x3cf2f373365347ed, 0x405c0e8405fdb642),
151 (0x3d276a94c8f1e627, 0xc0885e4718dfb761),
152 (0x3d569f8a993434e2, 0x40b756d52d5fa90c),
153 (0xbd6f953f7dd1a223, 0xc0c8818365c47790),
154 (0xbd74247967fbf7b2, 0x40e8cf89daf87353),
155 (0x3db449add7abb056, 0x41145d3c2d96d159),
156 (0xbdc5cc822b71f891, 0xc123694c58fd039b),
157 (0x3da2047ac1a6fba8, 0x415462e630bf3e7e),
158 (0xbdc2f2c06eda6a95, 0xc14c6984ebdd6792),
159 (0xbdf51fa85dafeca5, 0x4166a437c202d27b),
160 ];
161
162 let x2 = DoubleDouble::quick_mult(recip, recip);
163 let x4 = DoubleDouble::quick_mult(x2, x2);
164 let x8 = DoubleDouble::quick_mult(x4, x4);
165
166 let e0 = DoubleDouble::mul_add(
167 recip,
168 DoubleDouble::from_bit_pair(P[1]),
169 DoubleDouble::from_bit_pair(P[0]),
170 );
171 let e1 = DoubleDouble::mul_add(
172 recip,
173 DoubleDouble::from_bit_pair(P[3]),
174 DoubleDouble::from_bit_pair(P[2]),
175 );
176 let e2 = DoubleDouble::mul_add(
177 recip,
178 DoubleDouble::from_bit_pair(P[5]),
179 DoubleDouble::from_bit_pair(P[4]),
180 );
181 let e3 = DoubleDouble::mul_add(
182 recip,
183 DoubleDouble::from_bit_pair(P[7]),
184 DoubleDouble::from_bit_pair(P[6]),
185 );
186 let e4 = DoubleDouble::mul_add(
187 recip,
188 DoubleDouble::from_bit_pair(P[9]),
189 DoubleDouble::from_bit_pair(P[8]),
190 );
191 let e5 = DoubleDouble::mul_add(
192 recip,
193 DoubleDouble::from_bit_pair(P[11]),
194 DoubleDouble::from_bit_pair(P[10]),
195 );
196
197 let f0 = DoubleDouble::mul_add(x2, e1, e0);
198 let f1 = DoubleDouble::mul_add(x2, e3, e2);
199 let f2 = DoubleDouble::mul_add(x2, e5, e4);
200
201 let g0 = DoubleDouble::mul_add(x4, f1, f0);
202
203 let p_num = DoubleDouble::mul_add(x8, f2, g0);
204
205 const Q: [(u64, u64); 12] = [
206 (0x0000000000000000, 0x3ff0000000000000),
207 (0x3cde08e4cbf324d1, 0xc030b67bd69af0ca),
208 (0x3cec5e4ee7e77024, 0x4071b54c0f58409c),
209 (0xbd340e1131739e2f, 0xc09f140a738b14b3),
210 (0x3d607673189d6644, 0x40cdb44bd822add2),
211 (0xbd7793a4f1dd74d1, 0xc0e03fe2689b802d),
212 (0xbd8415501228a87e, 0x410009beafea72cc),
213 (0x3dcecdac2702661f, 0x4128c2073da9a447),
214 (0xbdd8386404f3dec5, 0xc1389ec7d7186bf4),
215 (0xbe06eb53a3e86436, 0x4168b7a2dc85ed0b),
216 (0x3e098e2cefaf8299, 0xc1604f8cf34af02c),
217 (0x3e1a5e496b547001, 0x41776b1e0153d1e9),
218 ];
219
220 let e0 = DoubleDouble::mul_add_f64(
221 recip,
222 DoubleDouble::from_bit_pair(Q[1]),
223 f64::from_bits(0x3ff0000000000000),
224 );
225 let e1 = DoubleDouble::mul_add(
226 recip,
227 DoubleDouble::from_bit_pair(Q[3]),
228 DoubleDouble::from_bit_pair(Q[2]),
229 );
230 let e2 = DoubleDouble::mul_add(
231 recip,
232 DoubleDouble::from_bit_pair(Q[5]),
233 DoubleDouble::from_bit_pair(Q[4]),
234 );
235 let e3 = DoubleDouble::mul_add(
236 recip,
237 DoubleDouble::from_bit_pair(Q[7]),
238 DoubleDouble::from_bit_pair(Q[6]),
239 );
240 let e4 = DoubleDouble::mul_add(
241 recip,
242 DoubleDouble::from_bit_pair(Q[9]),
243 DoubleDouble::from_bit_pair(Q[8]),
244 );
245 let e5 = DoubleDouble::mul_add(
246 recip,
247 DoubleDouble::from_bit_pair(Q[11]),
248 DoubleDouble::from_bit_pair(Q[10]),
249 );
250
251 let f0 = DoubleDouble::mul_add(x2, e1, e0);
252 let f1 = DoubleDouble::mul_add(x2, e3, e2);
253 let f2 = DoubleDouble::mul_add(x2, e5, e4);
254
255 let g0 = DoubleDouble::mul_add(x4, f1, f0);
256
257 let p_den = DoubleDouble::mul_add(x8, f2, g0);
258
259 let z = DoubleDouble::div(p_num, p_den);
260
261 let r_sqrt = DoubleDouble::from_rsqrt_fast(dx);
262 let r = z * r_sqrt;
263
264 let err = f_fmla(
265 r.hi,
266 f64::from_bits(0x3bc0000000000000),
267 f64::from_bits(0x392bdb8cdadbe111),
268 );
269 let up = r.hi + (r.lo + err);
270 let lb = r.hi + (r.lo - err);
271 if up != lb {
272 return i0e_7p5_to_9p5_hard(x);
273 }
274 r.to_f64()
275}
276
277#[cold]
296#[inline(never)]
297fn i0e_7p5_to_9p5_hard(x: f64) -> f64 {
298 static P: [DyadicFloat128; 14] = [
299 DyadicFloat128 {
300 sign: DyadicSign::Pos,
301 exponent: -129,
302 mantissa: 0xcc422a04_45cde144_75a3800b_45c38460_u128,
303 },
304 DyadicFloat128 {
305 sign: DyadicSign::Neg,
306 exponent: -124,
307 mantissa: 0xada66144_fcccc1a3_036f76b2_cabd6281_u128,
308 },
309 DyadicFloat128 {
310 sign: DyadicSign::Pos,
311 exponent: -120,
312 mantissa: 0xeabdda02_fa201d98_10e58d1f_7eb62bd7_u128,
313 },
314 DyadicFloat128 {
315 sign: DyadicSign::Neg,
316 exponent: -116,
317 mantissa: 0xbbfd3297_6f88a7df_5924587b_d5bdcdb8_u128,
318 },
319 DyadicFloat128 {
320 sign: DyadicSign::Pos,
321 exponent: -113,
322 mantissa: 0xfca29453_efe393bf_1651627b_7d543875_u128,
323 },
324 DyadicFloat128 {
325 sign: DyadicSign::Neg,
326 exponent: -110,
327 mantissa: 0xee7c7220_bbbd248e_bb6adac6_f9a5ce95_u128,
328 },
329 DyadicFloat128 {
330 sign: DyadicSign::Pos,
331 exponent: -107,
332 mantissa: 0xc07455dd_830ba705_414408c6_06732a5a_u128,
333 },
334 DyadicFloat128 {
335 sign: DyadicSign::Neg,
336 exponent: -105,
337 mantissa: 0xe2247793_b50cd0f0_80e8981d_933f75da_u128,
338 },
339 DyadicFloat128 {
340 sign: DyadicSign::Pos,
341 exponent: -103,
342 mantissa: 0xe14a9831_82582a0b_dd27e8b6_4ed9aac2_u128,
343 },
344 DyadicFloat128 {
345 sign: DyadicSign::Neg,
346 exponent: -101,
347 mantissa: 0xa3b2ae2f_5b64f37e_c1538435_34f02faf_u128,
348 },
349 DyadicFloat128 {
350 sign: DyadicSign::Pos,
351 exponent: -100,
352 mantissa: 0xbab73503_5b7e38d9_bbe4a84b_9007c6e8_u128,
353 },
354 DyadicFloat128 {
355 sign: DyadicSign::Neg,
356 exponent: -99,
357 mantissa: 0xa68911fc_5d87bbe7_0d4fe854_5c681ac5_u128,
358 },
359 DyadicFloat128 {
360 sign: DyadicSign::Pos,
361 exponent: -99,
362 mantissa: 0x9e997222_55ef4045_fa9f311d_57d082a2_u128,
363 },
364 DyadicFloat128 {
365 sign: DyadicSign::Neg,
366 exponent: -99,
367 mantissa: 0xbe93656a_b0a4f32d_3ebbfdeb_b1cbb839_u128,
368 },
369 ];
370 static Q: [DyadicFloat128; 14] = [
371 DyadicFloat128 {
372 sign: DyadicSign::Pos,
373 exponent: -127,
374 mantissa: 0x80000000_00000000_00000000_00000000_u128,
375 },
376 DyadicFloat128 {
377 sign: DyadicSign::Neg,
378 exponent: -123,
379 mantissa: 0xdaa34a7e_861dddff_a0642080_cd83dd65_u128,
380 },
381 DyadicFloat128 {
382 sign: DyadicSign::Pos,
383 exponent: -118,
384 mantissa: 0x93f05740_f4758772_bb9992f9_91e72795_u128,
385 },
386 DyadicFloat128 {
387 sign: DyadicSign::Neg,
388 exponent: -115,
389 mantissa: 0xeddcb810_054c9aab_fa7e4214_d59d18b0_u128,
390 },
391 DyadicFloat128 {
392 sign: DyadicSign::Pos,
393 exponent: -111,
394 mantissa: 0xa0180fcd_831ff6c0_ac2b8f02_37f3cfd1_u128,
395 },
396 DyadicFloat128 {
397 sign: DyadicSign::Neg,
398 exponent: -108,
399 mantissa: 0x97d25106_3b66907e_90b4f786_26daa0bb_u128,
400 },
401 DyadicFloat128 {
402 sign: DyadicSign::Pos,
403 exponent: -106,
404 mantissa: 0xf595ce38_aac16c11_001b874a_99603b45_u128,
405 },
406 DyadicFloat128 {
407 sign: DyadicSign::Neg,
408 exponent: -103,
409 mantissa: 0x912b3715_4aca68f6_5821c2ed_43d77111_u128,
410 },
411 DyadicFloat128 {
412 sign: DyadicSign::Pos,
413 exponent: -101,
414 mantissa: 0x90f97141_b896e2b6_38b87354_8945a43c_u128,
415 },
416 DyadicFloat128 {
417 sign: DyadicSign::Neg,
418 exponent: -100,
419 mantissa: 0xd3e5f967_89097d6b_3a3060fe_852ff580_u128,
420 },
421 DyadicFloat128 {
422 sign: DyadicSign::Pos,
423 exponent: -99,
424 mantissa: 0xf0d6de35_939da009_9ced21fd_48af7281_u128,
425 },
426 DyadicFloat128 {
427 sign: DyadicSign::Neg,
428 exponent: -98,
429 mantissa: 0xd2a0b183_6ac613b2_6745ce1d_8ed1c323_u128,
430 },
431 DyadicFloat128 {
432 sign: DyadicSign::Pos,
433 exponent: -98,
434 mantissa: 0xbb9c089a_b7e939a2_732b3fb5_2e66cd77_u128,
435 },
436 DyadicFloat128 {
437 sign: DyadicSign::Neg,
438 exponent: -98,
439 mantissa: 0xcb2107c3_736bef81_609718c0_ba82cd8e_u128,
440 },
441 ];
442
443 let recip = DyadicFloat128::accurate_reciprocal(x);
444
445 let mut p_num = P[13];
446 for i in (0..13).rev() {
447 p_num = recip * p_num + P[i];
448 }
449 let mut p_den = Q[13];
450 for i in (0..13).rev() {
451 p_den = recip * p_den + Q[i];
452 }
453 let z = p_num * p_den.reciprocal();
454
455 let r_sqrt = bessel_rsqrt_hard(x, recip);
456 (z * r_sqrt).fast_as_f64()
457}
458
459#[inline]
477fn i0e_asympt(x: f64) -> f64 {
478 let dx = x;
479 let recip = DoubleDouble::from_quick_recip(x);
480 const P: [(u64, u64); 12] = [
481 (0xbc7ca19c5d824c54, 0x3fd9884533d43651),
482 (0x3cca32eb734e010e, 0xc03b7ca35caf42eb),
483 (0x3d03af8238d6f25e, 0x408b92cfcaa7070f),
484 (0xbd7a8ff7fdebed70, 0xc0d0a3be432cce93),
485 (0xbdababdb579bb076, 0x410a77dc51f1804d),
486 (0x3dc5e4e3c972832a, 0xc13cb0be2f74839c),
487 (0x3e01076f9b102e38, 0x41653b064cc61661),
488 (0xbe2157e700d445f4, 0xc184e1b076927460),
489 (0xbdfa4577156dde56, 0x41999e9653f9dc5f),
490 (0xbe47aa238a739ffe, 0xc1a130f6ded40c00),
491 (0xbe331b560b6fbf4a, 0x419317f11e674cae),
492 (0xbe0765596077d1e3, 0xc16024404db59d3f),
493 ];
494
495 let x2 = DoubleDouble::quick_mult(recip, recip);
496 let x4 = DoubleDouble::quick_mult(x2, x2);
497 let x8 = DoubleDouble::quick_mult(x4, x4);
498
499 let e0 = DoubleDouble::mul_add(
500 recip,
501 DoubleDouble::from_bit_pair(P[1]),
502 DoubleDouble::from_bit_pair(P[0]),
503 );
504 let e1 = DoubleDouble::mul_add(
505 recip,
506 DoubleDouble::from_bit_pair(P[3]),
507 DoubleDouble::from_bit_pair(P[2]),
508 );
509 let e2 = DoubleDouble::mul_add(
510 recip,
511 DoubleDouble::from_bit_pair(P[5]),
512 DoubleDouble::from_bit_pair(P[4]),
513 );
514 let e3 = DoubleDouble::mul_add(
515 recip,
516 DoubleDouble::from_bit_pair(P[7]),
517 DoubleDouble::from_bit_pair(P[6]),
518 );
519 let e4 = DoubleDouble::mul_add(
520 recip,
521 DoubleDouble::from_bit_pair(P[9]),
522 DoubleDouble::from_bit_pair(P[8]),
523 );
524 let e5 = DoubleDouble::mul_add(
525 recip,
526 DoubleDouble::from_bit_pair(P[11]),
527 DoubleDouble::from_bit_pair(P[10]),
528 );
529
530 let f0 = DoubleDouble::mul_add(x2, e1, e0);
531 let f1 = DoubleDouble::mul_add(x2, e3, e2);
532 let f2 = DoubleDouble::mul_add(x2, e5, e4);
533
534 let g0 = DoubleDouble::mul_add(x4, f1, f0);
535
536 let p_num = DoubleDouble::mul_add(x8, f2, g0);
537
538 const Q: [(u64, u64); 12] = [
539 (0x0000000000000000, 0x3ff0000000000000),
540 (0xbcf687703e843d07, 0xc051418f1c4dd0b9),
541 (0x3d468ab92cb87a0b, 0x40a15891d823e48d),
542 (0x3d8bfc17e5183376, 0xc0e4fce40dd82796),
543 (0xbdccbbcc2ecf8d4c, 0x4120beef869c61ec),
544 (0xbdf42170b4d5d150, 0xc1523ad18834a7ed),
545 (0xbe0eaa32f405afd4, 0x417b24ec57a8f480),
546 (0x3e3ec900705e7252, 0xc19af2a91d23d62e),
547 (0x3e3e220e274fa46b, 0x41b0cb905cc99ff5),
548 (0xbe46c6c61dee11f6, 0xc1b7452e50518520),
549 (0x3e3ed0fc063187bf, 0x41ac1772d1749896),
550 (0xbe11c578f04f4be1, 0xc180feb5b2ca47cb),
551 ];
552
553 let e0 = DoubleDouble::mul_add_f64(
554 recip,
555 DoubleDouble::from_bit_pair(Q[1]),
556 f64::from_bits(0x3ff0000000000000),
557 );
558 let e1 = DoubleDouble::mul_add(
559 recip,
560 DoubleDouble::from_bit_pair(Q[3]),
561 DoubleDouble::from_bit_pair(Q[2]),
562 );
563 let e2 = DoubleDouble::mul_add(
564 recip,
565 DoubleDouble::from_bit_pair(Q[5]),
566 DoubleDouble::from_bit_pair(Q[4]),
567 );
568 let e3 = DoubleDouble::mul_add(
569 recip,
570 DoubleDouble::from_bit_pair(Q[7]),
571 DoubleDouble::from_bit_pair(Q[6]),
572 );
573 let e4 = DoubleDouble::mul_add(
574 recip,
575 DoubleDouble::from_bit_pair(Q[9]),
576 DoubleDouble::from_bit_pair(Q[8]),
577 );
578 let e5 = DoubleDouble::mul_add(
579 recip,
580 DoubleDouble::from_bit_pair(Q[11]),
581 DoubleDouble::from_bit_pair(Q[10]),
582 );
583
584 let f0 = DoubleDouble::mul_add(x2, e1, e0);
585 let f1 = DoubleDouble::mul_add(x2, e3, e2);
586 let f2 = DoubleDouble::mul_add(x2, e5, e4);
587
588 let g0 = DoubleDouble::mul_add(x4, f1, f0);
589
590 let p_den = DoubleDouble::mul_add(x8, f2, g0);
591
592 let z = DoubleDouble::div(p_num, p_den);
593
594 let r_sqrt = DoubleDouble::from_rsqrt_fast(dx);
595 let r = z * r_sqrt;
596 let err = f_fmla(
597 r.hi,
598 f64::from_bits(0x3c40000000000000), f64::from_bits(0x3be0000000000000), );
601 let up = r.hi + (r.lo + err);
602 let lb = r.hi + (r.lo - err);
603 if up != lb {
604 return i0e_asympt_hard(x);
605 }
606 lb
607}
608
609#[cold]
627#[inline(never)]
628fn i0e_asympt_hard(x: f64) -> f64 {
629 static P: [DyadicFloat128; 16] = [
630 DyadicFloat128 {
631 sign: DyadicSign::Pos,
632 exponent: -129,
633 mantissa: 0xcc42299e_a1b28468_7e5aad4a_70b749c4_u128,
634 },
635 DyadicFloat128 {
636 sign: DyadicSign::Neg,
637 exponent: -122,
638 mantissa: 0xabb4209d_ca11bdaa_186bef7f_390e6b77_u128,
639 },
640 DyadicFloat128 {
641 sign: DyadicSign::Pos,
642 exponent: -116,
643 mantissa: 0x8a2725e2_4749db25_625ad1f2_12a2a16c_u128,
644 },
645 DyadicFloat128 {
646 sign: DyadicSign::Neg,
647 exponent: -111,
648 mantissa: 0x8b4c2cd4_9e5d0c8b_c9be4d3e_781bb676_u128,
649 },
650 DyadicFloat128 {
651 sign: DyadicSign::Pos,
652 exponent: -107,
653 mantissa: 0xc33fad7c_40599f7d_713e3081_6b5ad791_u128,
654 },
655 DyadicFloat128 {
656 sign: DyadicSign::Neg,
657 exponent: -103,
658 mantissa: 0xc81da271_b623ba88_0be032b5_827d92fa_u128,
659 },
660 DyadicFloat128 {
661 sign: DyadicSign::Pos,
662 exponent: -99,
663 mantissa: 0x99ec4975_b6aa7cae_7692a287_ed8ae47c_u128,
664 },
665 DyadicFloat128 {
666 sign: DyadicSign::Neg,
667 exponent: -96,
668 mantissa: 0xb3aa4745_fc2dd441_2dbd3e3c_d4539687_u128,
669 },
670 DyadicFloat128 {
671 sign: DyadicSign::Pos,
672 exponent: -93,
673 mantissa: 0x9f14edc2_6882afca_29d2a067_dc459729_u128,
674 },
675 DyadicFloat128 {
676 sign: DyadicSign::Neg,
677 exponent: -91,
678 mantissa: 0xd35c4d01_78d8cec6_fc8ae0ee_834da837_u128,
679 },
680 DyadicFloat128 {
681 sign: DyadicSign::Pos,
682 exponent: -89,
683 mantissa: 0xcdc529c7_6e082342_faad3073_07a9b61f_u128,
684 },
685 DyadicFloat128 {
686 sign: DyadicSign::Neg,
687 exponent: -87,
688 mantissa: 0x8ccac88f_2598c8a6_423b1f42_63591cb9_u128,
689 },
690 DyadicFloat128 {
691 sign: DyadicSign::Pos,
692 exponent: -87,
693 mantissa: 0xfc044cfb_a20f0885_93d58660_17819ed5_u128,
694 },
695 DyadicFloat128 {
696 sign: DyadicSign::Neg,
697 exponent: -86,
698 mantissa: 0x813a700c_74d23f52_f81b179d_7ff0da9f_u128,
699 },
700 DyadicFloat128 {
701 sign: DyadicSign::Pos,
702 exponent: -88,
703 mantissa: 0xe6c43da4_297216bf_bdd987cb_636906cf_u128,
704 },
705 DyadicFloat128 {
706 sign: DyadicSign::Neg,
707 exponent: -91,
708 mantissa: 0xa4998323_649c3cf2_64477869_3d2c6afd_u128,
709 },
710 ];
711 static Q: [DyadicFloat128; 16] = [
712 DyadicFloat128 {
713 sign: DyadicSign::Pos,
714 exponent: -127,
715 mantissa: 0x80000000_00000000_00000000_00000000_u128,
716 },
717 DyadicFloat128 {
718 sign: DyadicSign::Neg,
719 exponent: -121,
720 mantissa: 0xd772d5fd_a7077638_6e007274_d83b013c_u128,
721 },
722 DyadicFloat128 {
723 sign: DyadicSign::Pos,
724 exponent: -115,
725 mantissa: 0xad914ef0_451ced2e_515657ef_fc7eeb53_u128,
726 },
727 DyadicFloat128 {
728 sign: DyadicSign::Neg,
729 exponent: -110,
730 mantissa: 0xaf41180c_dffe96e5_f192fa40_0b1bff1e_u128,
731 },
732 DyadicFloat128 {
733 sign: DyadicSign::Pos,
734 exponent: -106,
735 mantissa: 0xf60dc728_241f71fd_5b93e653_ccbedace_u128,
736 },
737 DyadicFloat128 {
738 sign: DyadicSign::Neg,
739 exponent: -102,
740 mantissa: 0xfcaefef9_39cf96e7_3cb75a98_da5e9761_u128,
741 },
742 DyadicFloat128 {
743 sign: DyadicSign::Pos,
744 exponent: -98,
745 mantissa: 0xc2d2c837_5789587a_13ef38c6_a24c3413_u128,
746 },
747 DyadicFloat128 {
748 sign: DyadicSign::Neg,
749 exponent: -95,
750 mantissa: 0xe41725c3_51d14486_a650044e_e8588f7b_u128,
751 },
752 DyadicFloat128 {
753 sign: DyadicSign::Pos,
754 exponent: -92,
755 mantissa: 0xcabeed9b_5e2e888d_81d32b11_d289a624_u128,
756 },
757 DyadicFloat128 {
758 sign: DyadicSign::Neg,
759 exponent: -89,
760 mantissa: 0x8764876d_11ad6607_8a8d5382_3ffe82d9_u128,
761 },
762 DyadicFloat128 {
763 sign: DyadicSign::Pos,
764 exponent: -87,
765 mantissa: 0x84c9f9e5_6a5f5034_ad2c8512_16cb1ba1_u128,
766 },
767 DyadicFloat128 {
768 sign: DyadicSign::Neg,
769 exponent: -86,
770 mantissa: 0xb7c1d143_a15d8aab_03a7fa3e_b7d07a36_u128,
771 },
772 DyadicFloat128 {
773 sign: DyadicSign::Pos,
774 exponent: -85,
775 mantissa: 0xa78f8257_4658040f_7a1ad39c_91ea9483_u128,
776 },
777 DyadicFloat128 {
778 sign: DyadicSign::Neg,
779 exponent: -85,
780 mantissa: 0xb231e0ca_b729a404_44c38f52_be208507_u128,
781 },
782 DyadicFloat128 {
783 sign: DyadicSign::Pos,
784 exponent: -86,
785 mantissa: 0xae317981_42349081_8bc68b28_f69b8e49_u128,
786 },
787 DyadicFloat128 {
788 sign: DyadicSign::Neg,
789 exponent: -89,
790 mantissa: 0xb451abd3_5cd79c6d_7e578164_32f16da1_u128,
791 },
792 ];
793
794 let recip = DyadicFloat128::accurate_reciprocal(x);
795
796 let mut p_num = P[15];
797 for i in (0..15).rev() {
798 p_num = recip * p_num + P[i];
799 }
800
801 let mut p_den = Q[15];
802 for i in (0..15).rev() {
803 p_den = recip * p_den + Q[i];
804 }
805
806 let z = p_num * p_den.reciprocal();
807
808 let r_sqrt = bessel_rsqrt_hard(x, recip);
809 (z * r_sqrt).fast_as_f64()
810}
811
812#[cfg(test)]
813mod tests {
814 use super::*;
815 #[test]
816 fn test_i0e() {
817 assert_eq!(f_i0e(0.00000000000000000000000000052342), 1.0);
818 assert_eq!(f_i0e(f64::EPSILON), 0.9999999999999998);
819 assert_eq!(f_i0e(9.500000000005492,), 0.13125126081422883);
820 assert!(f_i0e(f64::NAN).is_nan());
821 assert_eq!(f_i0e(f64::INFINITY), 0.);
822 assert_eq!(f_i0e(f64::NEG_INFINITY), 0.);
823 assert_eq!(f_i0e(7.500000000788034), 0.14831583006929877);
824 assert_eq!(f_i0e(715.), 0.014922205745802662);
825 assert_eq!(f_i0e(12.), 0.11642622121344044);
826 assert_eq!(f_i0e(16.), 0.10054412736125203);
827 assert_eq!(f_i0e(18.432), 0.09357372647647);
828 assert_eq!(f_i0e(26.432), 0.07797212360059241);
829 assert_eq!(f_i0e(0.2), 0.8269385516343293);
830 assert_eq!(f_i0e(7.5), 0.14831583007739552);
831 assert_eq!(f_i0e(-1.5), 0.36743360905415834);
832 assert_eq!(i0e_asympt_hard(18.432), 0.09357372647647);
833 }
834}