1use crate::bessel::bessel_exp::i0_exp;
30use crate::common::f_fmla;
31use crate::double_double::DoubleDouble;
32use crate::dyadic_float::{DyadicFloat128, DyadicSign};
33use crate::exponents::rational128_exp;
34use crate::polyeval::{f_estrin_polyeval5, f_polyeval4};
35
36pub fn f_i0(x: f64) -> f64 {
40 let ux = x.to_bits().wrapping_shl(1);
41
42 if ux >= 0x7ffu64 << 53 || ux <= 0x7960000000000000u64 {
43 if ux <= 0x760af31dc4611874u64 {
45 return 1.;
47 }
48 if ux <= 0x7960000000000000u64 {
49 let half_x = x * 0.5;
52 return f_fmla(half_x, half_x, 1.);
53 }
54 if x.is_infinite() {
55 return f64::INFINITY;
56 }
57 return x + f64::NAN; }
59
60 let xb = x.to_bits() & 0x7fff_ffff_ffff_ffff;
61
62 if xb > 0x40864fe5304e83e4u64 {
63 return f64::INFINITY;
65 }
66
67 if xb <= 0x4023000000000000u64 {
68 if xb <= 0x400ccccccccccccdu64 {
70 return i0_0_to_3p6_exec(f64::from_bits(xb));
72 } else if xb <= 0x401e000000000000u64 {
73 return i3p6_to_7p5(f64::from_bits(xb));
75 }
76 return i0_7p5_to_9p5(f64::from_bits(xb));
77 }
78
79 i0_asympt(f64::from_bits(xb))
80}
81
82#[inline]
86fn i3p6_to_7p5(x: f64) -> f64 {
87 let r = i0_3p6_to_7p5_dd(x);
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 eval_small_hard_3p6_to_7p5(x).to_f64();
98 }
99 r.to_f64()
100}
101
102#[inline]
124pub(crate) fn i0_0_to_3p6_dd(x: f64) -> DoubleDouble {
125 let half_x = x * 0.5; let eval_x = DoubleDouble::from_exact_mult(half_x, half_x);
127 const P: [(u64, u64); 8] = [
128 (0xba93dec1e5396e30, 0x3ff0000000000000),
129 (0xbc5d3d919a2b891a, 0x3fcb128f49a1f59f),
130 (0xbc3c4d80de165459, 0x3f9353508fce278f),
131 (0x3be7e0e75c00d411, 0x3f4b760657892e15),
132 (0xbb9bc959d02076a4, 0x3ef588ff0ba5872e),
133 (0x3b257756675180e4, 0x3e932e320d411521),
134 (0xbaca098436a47ec6, 0x3e2285f524a51de0),
135 (0x3a0e48fa0331db75, 0x3d9ee6518d82a209),
136 ];
137 let ps_num = f_estrin_polyeval5(
138 eval_x.hi,
139 f64::from_bits(0x3f4b760657892e15),
140 f64::from_bits(0x3ef588ff0ba5872e),
141 f64::from_bits(0x3e932e320d411521),
142 f64::from_bits(0x3e2285f524a51de0),
143 f64::from_bits(0x3d9ee6518d82a209),
144 );
145 let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[2]));
146 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1]));
147 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0]));
148 const Q: [(u64, u64); 7] = [
149 (0x0000000000000000, 0x3ff0000000000000),
150 (0x3c26136ec7050a58, 0xbfa3b5c2d9782985),
151 (0x3bdf9cd5be66297b, 0x3f478d5c030ea692),
152 (0xbb5036196d4b865c, 0xbee1a83b6e8c6fd6),
153 (0xbb1a9dafadc75858, 0x3e71ba443893032b),
154 (0xba7a719ba9ed7e7f, 0xbdf6e673af3e0c66),
155 (0xb9e17740b37a23ec, 0x3d6e2c993fef696f),
156 ];
157 let ps_den = f_polyeval4(
158 eval_x.hi,
159 f64::from_bits(0xbee1a83b6e8c6fd6),
160 f64::from_bits(0x3e71ba443893032b),
161 f64::from_bits(0xbdf6e673af3e0c66),
162 f64::from_bits(0x3d6e2c993fef696f),
163 );
164 let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[2]));
165 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1]));
166 p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000));
167 DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.)
168}
169
170#[inline]
184pub(crate) fn i0_3p6_to_7p5_dd(x: f64) -> DoubleDouble {
185 let half_x = x * 0.5; let eval_x = DoubleDouble::from_exact_mult(half_x, half_x);
187 const P: [(u64, u64); 10] = [
188 (0xbae8195e94c833a1, 0x3ff0000000000000),
189 (0xbc6f4db3a04cf778, 0x3fcbca374cf8efde),
190 (0x3c31e334a32ed081, 0x3f9493391f88f49c),
191 (0x3bb77456438b622e, 0x3f4f2aff2cd821b7),
192 (0x3b312b847b83fa80, 0x3efb249e459c00fa),
193 (0x3b1d3faf77d3ee5b, 0x3e9cd199c39f6d6c),
194 (0xbaaf6a6a3d483df8, 0x3e331192e34cb81f),
195 (0x3a406e234cb7aede, 0x3dbef6023ba17d1a),
196 (0x39dee1ec666e30b5, 0x3d3c8bab78d825e9),
197 (0x3910b9821c993936, 0x3ca73bf438398234),
198 ];
199 let ps_num = f_estrin_polyeval5(
200 eval_x.hi,
201 f64::from_bits(0x3e9cd199c39f6d6c),
202 f64::from_bits(0x3e331192e34cb81f),
203 f64::from_bits(0x3dbef6023ba17d1a),
204 f64::from_bits(0x3d3c8bab78d825e9),
205 f64::from_bits(0x3ca73bf438398234),
206 );
207 let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[4]));
208 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3]));
209 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2]));
210 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1]));
211 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0]));
212 const Q: [(u64, u64); 10] = [
213 (0x0000000000000000, 0x3ff0000000000000),
214 (0x3c16498103ae0f29, 0xbfa0d722cc1c408a),
215 (0x3ba9b44df49b7368, 0x3f41a06d24a9b89a),
216 (0x3b43ef4989b8a3ed, 0xbed8363c48ecd98c),
217 (0xbaf6197838a8a2ef, 0x3e6830647038f0ac),
218 (0x3a96c443c7d52296, 0xbdf257666a799e31),
219 (0x3a118e8a97f0df20, 0x3d753ffeb530f0c8),
220 (0xb99e90b659ab1bb7, 0xbcf243374f2b7d6c),
221 (0x38f647cfef513fc5, 0x3c654740fd120da3),
222 (0x386d691099d0e8fc, 0xbbc9c9c826756a76),
223 ];
224 let ps_den = f_estrin_polyeval5(
225 eval_x.hi,
226 f64::from_bits(0xbdf257666a799e31),
227 f64::from_bits(0x3d753ffeb530f0c8),
228 f64::from_bits(0xbcf243374f2b7d6c),
229 f64::from_bits(0x3c654740fd120da3),
230 f64::from_bits(0xbbc9c9c826756a76),
231 );
232 let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[4]));
233 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3]));
234 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2]));
235 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1]));
236 p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000));
237 DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.)
238}
239
240#[cold]
254#[inline(never)]
255pub(crate) fn eval_small_hard_3p6_to_7p5(x: f64) -> DoubleDouble {
256 let half_x = x * 0.5; let eval_x = DoubleDouble::from_exact_mult(half_x, half_x);
258 const P: [(u64, u64); 10] = [
259 (0xbae8195e94c833a1, 0x3ff0000000000000),
260 (0xbc6f4db3a04cf778, 0x3fcbca374cf8efde),
261 (0x3c31e334a32ed081, 0x3f9493391f88f49c),
262 (0x3bb77456438b622e, 0x3f4f2aff2cd821b7),
263 (0x3b312b847b83fa80, 0x3efb249e459c00fa),
264 (0x3b1d3faf77d3ee5b, 0x3e9cd199c39f6d6c),
265 (0xbaaf6a6a3d483df8, 0x3e331192e34cb81f),
266 (0x3a406e234cb7aede, 0x3dbef6023ba17d1a),
267 (0x39dee1ec666e30b5, 0x3d3c8bab78d825e9),
268 (0x3910b9821c993936, 0x3ca73bf438398234),
269 ];
270 let mut p_num = DoubleDouble::mul_add(
271 eval_x,
272 DoubleDouble::from_bit_pair(P[9]),
273 DoubleDouble::from_bit_pair(P[8]),
274 );
275 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[7]));
276 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[6]));
277 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[5]));
278 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[4]));
279 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3]));
280 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2]));
281 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1]));
282 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0]));
283 const Q: [(u64, u64); 10] = [
284 (0x0000000000000000, 0x3ff0000000000000),
285 (0x3c16498103ae0f29, 0xbfa0d722cc1c408a),
286 (0x3ba9b44df49b7368, 0x3f41a06d24a9b89a),
287 (0x3b43ef4989b8a3ed, 0xbed8363c48ecd98c),
288 (0xbaf6197838a8a2ef, 0x3e6830647038f0ac),
289 (0x3a96c443c7d52296, 0xbdf257666a799e31),
290 (0x3a118e8a97f0df20, 0x3d753ffeb530f0c8),
291 (0xb99e90b659ab1bb7, 0xbcf243374f2b7d6c),
292 (0x38f647cfef513fc5, 0x3c654740fd120da3),
293 (0x386d691099d0e8fc, 0xbbc9c9c826756a76),
294 ];
295 let mut p_den = DoubleDouble::mul_add(
296 eval_x,
297 DoubleDouble::from_bit_pair(Q[9]),
298 DoubleDouble::from_bit_pair(Q[8]),
299 );
300 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[7]));
301 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[6]));
302 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[5]));
303 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[4]));
304 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3]));
305 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2]));
306 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1]));
307 p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000));
308 DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.)
309}
310
311#[inline]
312pub(crate) fn i0_0_to_3p6_exec(x: f64) -> f64 {
313 let r = i0_0_to_3p6_dd(x);
314 let err = f_fmla(
315 r.hi,
316 f64::from_bits(0x3c40000000000000), f64::from_bits(0x3be0000000000000), );
319 let ub = r.hi + (r.lo + err);
320 let lb = r.hi + (r.lo - err);
321 if ub == lb {
322 return r.to_f64();
323 }
324 i0_0_to_3p6_hard(x).to_f64()
325}
326
327#[cold]
340#[inline(never)]
341pub(crate) fn i0_0_to_3p6_hard(x: f64) -> DoubleDouble {
342 let half_x = x * 0.5; let eval_x = DoubleDouble::from_exact_mult(half_x, half_x);
344 const P: [(u64, u64); 8] = [
345 (0xba93dec1e5396e30, 0x3ff0000000000000),
346 (0xbc5d3d919a2b891a, 0x3fcb128f49a1f59f),
347 (0xbc3c4d80de165459, 0x3f9353508fce278f),
348 (0x3be7e0e75c00d411, 0x3f4b760657892e15),
349 (0xbb9bc959d02076a4, 0x3ef588ff0ba5872e),
350 (0x3b257756675180e4, 0x3e932e320d411521),
351 (0xbaca098436a47ec6, 0x3e2285f524a51de0),
352 (0x3a0e48fa0331db75, 0x3d9ee6518d82a209),
353 ];
354 let mut p_num = DoubleDouble::mul_add(
355 eval_x,
356 DoubleDouble::from_bit_pair(P[7]),
357 DoubleDouble::from_bit_pair(P[6]),
358 );
359 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[5]));
360 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[4]));
361 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3]));
362 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2]));
363 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1]));
364 p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0]));
365 const Q: [(u64, u64); 7] = [
366 (0x0000000000000000, 0x3ff0000000000000),
367 (0x3c26136ec7050a58, 0xbfa3b5c2d9782985),
368 (0x3bdf9cd5be66297b, 0x3f478d5c030ea692),
369 (0xbb5036196d4b865c, 0xbee1a83b6e8c6fd6),
370 (0xbb1a9dafadc75858, 0x3e71ba443893032b),
371 (0xba7a719ba9ed7e7f, 0xbdf6e673af3e0c66),
372 (0xb9e17740b37a23ec, 0x3d6e2c993fef696f),
373 ];
374 let mut p_den = DoubleDouble::mul_add(
375 eval_x,
376 DoubleDouble::from_bit_pair(Q[6]),
377 DoubleDouble::from_bit_pair(Q[5]),
378 );
379 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[4]));
380 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3]));
381 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2]));
382 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1]));
383 p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0]));
384 DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.)
385}
386
387#[inline]
404fn i0_7p5_to_9p5(x: f64) -> f64 {
405 let dx = x;
406 let recip = DoubleDouble::from_quick_recip(x);
407
408 const P: [(u64, u64); 12] = [
409 (0x3c778e3de1f76f48, 0x3fd988450531281b),
410 (0xbcb572f6149f389e, 0xc01a786676fb4d3a),
411 (0x3cf2f373365347ed, 0x405c0e8405fdb642),
412 (0x3d276a94c8f1e627, 0xc0885e4718dfb761),
413 (0x3d569f8a993434e2, 0x40b756d52d5fa90c),
414 (0xbd6f953f7dd1a223, 0xc0c8818365c47790),
415 (0xbd74247967fbf7b2, 0x40e8cf89daf87353),
416 (0x3db449add7abb056, 0x41145d3c2d96d159),
417 (0xbdc5cc822b71f891, 0xc123694c58fd039b),
418 (0x3da2047ac1a6fba8, 0x415462e630bf3e7e),
419 (0xbdc2f2c06eda6a95, 0xc14c6984ebdd6792),
420 (0xbdf51fa85dafeca5, 0x4166a437c202d27b),
421 ];
422
423 let x2 = DoubleDouble::quick_mult(recip, recip);
424 let x4 = DoubleDouble::quick_mult(x2, x2);
425 let x8 = DoubleDouble::quick_mult(x4, x4);
426
427 let e0 = DoubleDouble::mul_add(
428 recip,
429 DoubleDouble::from_bit_pair(P[1]),
430 DoubleDouble::from_bit_pair(P[0]),
431 );
432 let e1 = DoubleDouble::mul_add(
433 recip,
434 DoubleDouble::from_bit_pair(P[3]),
435 DoubleDouble::from_bit_pair(P[2]),
436 );
437 let e2 = DoubleDouble::mul_add(
438 recip,
439 DoubleDouble::from_bit_pair(P[5]),
440 DoubleDouble::from_bit_pair(P[4]),
441 );
442 let e3 = DoubleDouble::mul_add(
443 recip,
444 DoubleDouble::from_bit_pair(P[7]),
445 DoubleDouble::from_bit_pair(P[6]),
446 );
447 let e4 = DoubleDouble::mul_add(
448 recip,
449 DoubleDouble::from_bit_pair(P[9]),
450 DoubleDouble::from_bit_pair(P[8]),
451 );
452 let e5 = DoubleDouble::mul_add(
453 recip,
454 DoubleDouble::from_bit_pair(P[11]),
455 DoubleDouble::from_bit_pair(P[10]),
456 );
457
458 let f0 = DoubleDouble::mul_add(x2, e1, e0);
459 let f1 = DoubleDouble::mul_add(x2, e3, e2);
460 let f2 = DoubleDouble::mul_add(x2, e5, e4);
461
462 let g0 = DoubleDouble::mul_add(x4, f1, f0);
463
464 let p_num = DoubleDouble::mul_add(x8, f2, g0);
465
466 const Q: [(u64, u64); 12] = [
467 (0x0000000000000000, 0x3ff0000000000000),
468 (0x3cde08e4cbf324d1, 0xc030b67bd69af0ca),
469 (0x3cec5e4ee7e77024, 0x4071b54c0f58409c),
470 (0xbd340e1131739e2f, 0xc09f140a738b14b3),
471 (0x3d607673189d6644, 0x40cdb44bd822add2),
472 (0xbd7793a4f1dd74d1, 0xc0e03fe2689b802d),
473 (0xbd8415501228a87e, 0x410009beafea72cc),
474 (0x3dcecdac2702661f, 0x4128c2073da9a447),
475 (0xbdd8386404f3dec5, 0xc1389ec7d7186bf4),
476 (0xbe06eb53a3e86436, 0x4168b7a2dc85ed0b),
477 (0x3e098e2cefaf8299, 0xc1604f8cf34af02c),
478 (0x3e1a5e496b547001, 0x41776b1e0153d1e9),
479 ];
480
481 let e0 = DoubleDouble::mul_add_f64(
482 recip,
483 DoubleDouble::from_bit_pair(Q[1]),
484 f64::from_bits(0x3ff0000000000000),
485 );
486 let e1 = DoubleDouble::mul_add(
487 recip,
488 DoubleDouble::from_bit_pair(Q[3]),
489 DoubleDouble::from_bit_pair(Q[2]),
490 );
491 let e2 = DoubleDouble::mul_add(
492 recip,
493 DoubleDouble::from_bit_pair(Q[5]),
494 DoubleDouble::from_bit_pair(Q[4]),
495 );
496 let e3 = DoubleDouble::mul_add(
497 recip,
498 DoubleDouble::from_bit_pair(Q[7]),
499 DoubleDouble::from_bit_pair(Q[6]),
500 );
501 let e4 = DoubleDouble::mul_add(
502 recip,
503 DoubleDouble::from_bit_pair(Q[9]),
504 DoubleDouble::from_bit_pair(Q[8]),
505 );
506 let e5 = DoubleDouble::mul_add(
507 recip,
508 DoubleDouble::from_bit_pair(Q[11]),
509 DoubleDouble::from_bit_pair(Q[10]),
510 );
511
512 let f0 = DoubleDouble::mul_add(x2, e1, e0);
513 let f1 = DoubleDouble::mul_add(x2, e3, e2);
514 let f2 = DoubleDouble::mul_add(x2, e5, e4);
515
516 let g0 = DoubleDouble::mul_add(x4, f1, f0);
517
518 let p_den = DoubleDouble::mul_add(x8, f2, g0);
519
520 let z = DoubleDouble::div(p_num, p_den);
521
522 let e = i0_exp(dx);
523 let r_sqrt = DoubleDouble::from_rsqrt_fast(dx);
524 let r = DoubleDouble::quick_mult(z * r_sqrt, e);
525
526 let err = f_fmla(
527 r.hi,
528 f64::from_bits(0x3bc0000000000000),
529 f64::from_bits(0x392bdb8cdadbe111),
530 );
531 let up = r.hi + (r.lo + err);
532 let lb = r.hi + (r.lo - err);
533 if up != lb {
534 return i0_7p5_to_9p5_hard(x);
535 }
536 r.to_f64()
537}
538
539#[cold]
558#[inline(never)]
559fn i0_7p5_to_9p5_hard(x: f64) -> f64 {
560 static P: [DyadicFloat128; 14] = [
561 DyadicFloat128 {
562 sign: DyadicSign::Pos,
563 exponent: -129,
564 mantissa: 0xcc422a04_45cde144_75a3800b_45c38460_u128,
565 },
566 DyadicFloat128 {
567 sign: DyadicSign::Neg,
568 exponent: -124,
569 mantissa: 0xada66144_fcccc1a3_036f76b2_cabd6281_u128,
570 },
571 DyadicFloat128 {
572 sign: DyadicSign::Pos,
573 exponent: -120,
574 mantissa: 0xeabdda02_fa201d98_10e58d1f_7eb62bd7_u128,
575 },
576 DyadicFloat128 {
577 sign: DyadicSign::Neg,
578 exponent: -116,
579 mantissa: 0xbbfd3297_6f88a7df_5924587b_d5bdcdb8_u128,
580 },
581 DyadicFloat128 {
582 sign: DyadicSign::Pos,
583 exponent: -113,
584 mantissa: 0xfca29453_efe393bf_1651627b_7d543875_u128,
585 },
586 DyadicFloat128 {
587 sign: DyadicSign::Neg,
588 exponent: -110,
589 mantissa: 0xee7c7220_bbbd248e_bb6adac6_f9a5ce95_u128,
590 },
591 DyadicFloat128 {
592 sign: DyadicSign::Pos,
593 exponent: -107,
594 mantissa: 0xc07455dd_830ba705_414408c6_06732a5a_u128,
595 },
596 DyadicFloat128 {
597 sign: DyadicSign::Neg,
598 exponent: -105,
599 mantissa: 0xe2247793_b50cd0f0_80e8981d_933f75da_u128,
600 },
601 DyadicFloat128 {
602 sign: DyadicSign::Pos,
603 exponent: -103,
604 mantissa: 0xe14a9831_82582a0b_dd27e8b6_4ed9aac2_u128,
605 },
606 DyadicFloat128 {
607 sign: DyadicSign::Neg,
608 exponent: -101,
609 mantissa: 0xa3b2ae2f_5b64f37e_c1538435_34f02faf_u128,
610 },
611 DyadicFloat128 {
612 sign: DyadicSign::Pos,
613 exponent: -100,
614 mantissa: 0xbab73503_5b7e38d9_bbe4a84b_9007c6e8_u128,
615 },
616 DyadicFloat128 {
617 sign: DyadicSign::Neg,
618 exponent: -99,
619 mantissa: 0xa68911fc_5d87bbe7_0d4fe854_5c681ac5_u128,
620 },
621 DyadicFloat128 {
622 sign: DyadicSign::Pos,
623 exponent: -99,
624 mantissa: 0x9e997222_55ef4045_fa9f311d_57d082a2_u128,
625 },
626 DyadicFloat128 {
627 sign: DyadicSign::Neg,
628 exponent: -99,
629 mantissa: 0xbe93656a_b0a4f32d_3ebbfdeb_b1cbb839_u128,
630 },
631 ];
632 static Q: [DyadicFloat128; 14] = [
633 DyadicFloat128 {
634 sign: DyadicSign::Pos,
635 exponent: -127,
636 mantissa: 0x80000000_00000000_00000000_00000000_u128,
637 },
638 DyadicFloat128 {
639 sign: DyadicSign::Neg,
640 exponent: -123,
641 mantissa: 0xdaa34a7e_861dddff_a0642080_cd83dd65_u128,
642 },
643 DyadicFloat128 {
644 sign: DyadicSign::Pos,
645 exponent: -118,
646 mantissa: 0x93f05740_f4758772_bb9992f9_91e72795_u128,
647 },
648 DyadicFloat128 {
649 sign: DyadicSign::Neg,
650 exponent: -115,
651 mantissa: 0xeddcb810_054c9aab_fa7e4214_d59d18b0_u128,
652 },
653 DyadicFloat128 {
654 sign: DyadicSign::Pos,
655 exponent: -111,
656 mantissa: 0xa0180fcd_831ff6c0_ac2b8f02_37f3cfd1_u128,
657 },
658 DyadicFloat128 {
659 sign: DyadicSign::Neg,
660 exponent: -108,
661 mantissa: 0x97d25106_3b66907e_90b4f786_26daa0bb_u128,
662 },
663 DyadicFloat128 {
664 sign: DyadicSign::Pos,
665 exponent: -106,
666 mantissa: 0xf595ce38_aac16c11_001b874a_99603b45_u128,
667 },
668 DyadicFloat128 {
669 sign: DyadicSign::Neg,
670 exponent: -103,
671 mantissa: 0x912b3715_4aca68f6_5821c2ed_43d77111_u128,
672 },
673 DyadicFloat128 {
674 sign: DyadicSign::Pos,
675 exponent: -101,
676 mantissa: 0x90f97141_b896e2b6_38b87354_8945a43c_u128,
677 },
678 DyadicFloat128 {
679 sign: DyadicSign::Neg,
680 exponent: -100,
681 mantissa: 0xd3e5f967_89097d6b_3a3060fe_852ff580_u128,
682 },
683 DyadicFloat128 {
684 sign: DyadicSign::Pos,
685 exponent: -99,
686 mantissa: 0xf0d6de35_939da009_9ced21fd_48af7281_u128,
687 },
688 DyadicFloat128 {
689 sign: DyadicSign::Neg,
690 exponent: -98,
691 mantissa: 0xd2a0b183_6ac613b2_6745ce1d_8ed1c323_u128,
692 },
693 DyadicFloat128 {
694 sign: DyadicSign::Pos,
695 exponent: -98,
696 mantissa: 0xbb9c089a_b7e939a2_732b3fb5_2e66cd77_u128,
697 },
698 DyadicFloat128 {
699 sign: DyadicSign::Neg,
700 exponent: -98,
701 mantissa: 0xcb2107c3_736bef81_609718c0_ba82cd8e_u128,
702 },
703 ];
704
705 let recip = DyadicFloat128::accurate_reciprocal(x);
706
707 let mut p_num = P[13];
708 for i in (0..13).rev() {
709 p_num = recip * p_num + P[i];
710 }
711 let mut p_den = Q[13];
712 for i in (0..13).rev() {
713 p_den = recip * p_den + Q[i];
714 }
715 let z = p_num * p_den.reciprocal();
716
717 let r_sqrt = bessel_rsqrt_hard(x, recip);
718 let f_exp = rational128_exp(x);
719 (z * r_sqrt * f_exp).fast_as_f64()
720}
721
722#[inline]
740fn i0_asympt(x: f64) -> f64 {
741 let dx = x;
742 let recip = DoubleDouble::from_quick_recip(x);
743 const P: [(u64, u64); 12] = [
744 (0xbc7ca19c5d824c54, 0x3fd9884533d43651),
745 (0x3cca32eb734e010e, 0xc03b7ca35caf42eb),
746 (0x3d03af8238d6f25e, 0x408b92cfcaa7070f),
747 (0xbd7a8ff7fdebed70, 0xc0d0a3be432cce93),
748 (0xbdababdb579bb076, 0x410a77dc51f1804d),
749 (0x3dc5e4e3c972832a, 0xc13cb0be2f74839c),
750 (0x3e01076f9b102e38, 0x41653b064cc61661),
751 (0xbe2157e700d445f4, 0xc184e1b076927460),
752 (0xbdfa4577156dde56, 0x41999e9653f9dc5f),
753 (0xbe47aa238a739ffe, 0xc1a130f6ded40c00),
754 (0xbe331b560b6fbf4a, 0x419317f11e674cae),
755 (0xbe0765596077d1e3, 0xc16024404db59d3f),
756 ];
757
758 let x2 = DoubleDouble::quick_mult(recip, recip);
759 let x4 = DoubleDouble::quick_mult(x2, x2);
760 let x8 = DoubleDouble::quick_mult(x4, x4);
761
762 let e0 = DoubleDouble::mul_add(
763 recip,
764 DoubleDouble::from_bit_pair(P[1]),
765 DoubleDouble::from_bit_pair(P[0]),
766 );
767 let e1 = DoubleDouble::mul_add(
768 recip,
769 DoubleDouble::from_bit_pair(P[3]),
770 DoubleDouble::from_bit_pair(P[2]),
771 );
772 let e2 = DoubleDouble::mul_add(
773 recip,
774 DoubleDouble::from_bit_pair(P[5]),
775 DoubleDouble::from_bit_pair(P[4]),
776 );
777 let e3 = DoubleDouble::mul_add(
778 recip,
779 DoubleDouble::from_bit_pair(P[7]),
780 DoubleDouble::from_bit_pair(P[6]),
781 );
782 let e4 = DoubleDouble::mul_add(
783 recip,
784 DoubleDouble::from_bit_pair(P[9]),
785 DoubleDouble::from_bit_pair(P[8]),
786 );
787 let e5 = DoubleDouble::mul_add(
788 recip,
789 DoubleDouble::from_bit_pair(P[11]),
790 DoubleDouble::from_bit_pair(P[10]),
791 );
792
793 let f0 = DoubleDouble::mul_add(x2, e1, e0);
794 let f1 = DoubleDouble::mul_add(x2, e3, e2);
795 let f2 = DoubleDouble::mul_add(x2, e5, e4);
796
797 let g0 = DoubleDouble::mul_add(x4, f1, f0);
798
799 let p_num = DoubleDouble::mul_add(x8, f2, g0);
800
801 const Q: [(u64, u64); 12] = [
802 (0x0000000000000000, 0x3ff0000000000000),
803 (0xbcf687703e843d07, 0xc051418f1c4dd0b9),
804 (0x3d468ab92cb87a0b, 0x40a15891d823e48d),
805 (0x3d8bfc17e5183376, 0xc0e4fce40dd82796),
806 (0xbdccbbcc2ecf8d4c, 0x4120beef869c61ec),
807 (0xbdf42170b4d5d150, 0xc1523ad18834a7ed),
808 (0xbe0eaa32f405afd4, 0x417b24ec57a8f480),
809 (0x3e3ec900705e7252, 0xc19af2a91d23d62e),
810 (0x3e3e220e274fa46b, 0x41b0cb905cc99ff5),
811 (0xbe46c6c61dee11f6, 0xc1b7452e50518520),
812 (0x3e3ed0fc063187bf, 0x41ac1772d1749896),
813 (0xbe11c578f04f4be1, 0xc180feb5b2ca47cb),
814 ];
815
816 let e0 = DoubleDouble::mul_add_f64(
817 recip,
818 DoubleDouble::from_bit_pair(Q[1]),
819 f64::from_bits(0x3ff0000000000000),
820 );
821 let e1 = DoubleDouble::mul_add(
822 recip,
823 DoubleDouble::from_bit_pair(Q[3]),
824 DoubleDouble::from_bit_pair(Q[2]),
825 );
826 let e2 = DoubleDouble::mul_add(
827 recip,
828 DoubleDouble::from_bit_pair(Q[5]),
829 DoubleDouble::from_bit_pair(Q[4]),
830 );
831 let e3 = DoubleDouble::mul_add(
832 recip,
833 DoubleDouble::from_bit_pair(Q[7]),
834 DoubleDouble::from_bit_pair(Q[6]),
835 );
836 let e4 = DoubleDouble::mul_add(
837 recip,
838 DoubleDouble::from_bit_pair(Q[9]),
839 DoubleDouble::from_bit_pair(Q[8]),
840 );
841 let e5 = DoubleDouble::mul_add(
842 recip,
843 DoubleDouble::from_bit_pair(Q[11]),
844 DoubleDouble::from_bit_pair(Q[10]),
845 );
846
847 let f0 = DoubleDouble::mul_add(x2, e1, e0);
848 let f1 = DoubleDouble::mul_add(x2, e3, e2);
849 let f2 = DoubleDouble::mul_add(x2, e5, e4);
850
851 let g0 = DoubleDouble::mul_add(x4, f1, f0);
852
853 let p_den = DoubleDouble::mul_add(x8, f2, g0);
854
855 let z = DoubleDouble::div(p_num, p_den);
856
857 let mut e = i0_exp(dx * 0.5);
858 e = DoubleDouble::from_exact_add(e.hi, e.lo);
859 let r_sqrt = DoubleDouble::from_rsqrt_fast(dx);
860 let r = DoubleDouble::quick_mult(z * r_sqrt * e, e);
861 let err = f_fmla(
862 r.hi,
863 f64::from_bits(0x3c40000000000000), f64::from_bits(0x3be0000000000000), );
866 let up = r.hi + (r.lo + err);
867 let lb = r.hi + (r.lo - err);
868 if up != lb {
869 return i0_asympt_hard(x);
870 }
871 lb
872}
873
874#[inline]
875pub(crate) fn bessel_rsqrt_hard(x: f64, recip: DyadicFloat128) -> DyadicFloat128 {
876 let r = DyadicFloat128::new_from_f64(x.sqrt()) * recip;
877 let fx = DyadicFloat128::new_from_f64(x);
878 let rx = r * fx;
879 let drx = r * fx - rx;
880 const M_ONE: DyadicFloat128 = DyadicFloat128 {
881 sign: DyadicSign::Neg,
882 exponent: -127,
883 mantissa: 0x80000000_00000000_00000000_00000000_u128,
884 };
885 let h = r * rx + M_ONE + r * drx;
886 let mut ddr = r;
887 ddr.exponent -= 1; let dr = ddr * h;
889 r - dr
890}
891
892#[cold]
910#[inline(never)]
911fn i0_asympt_hard(x: f64) -> f64 {
912 static P: [DyadicFloat128; 16] = [
913 DyadicFloat128 {
914 sign: DyadicSign::Pos,
915 exponent: -129,
916 mantissa: 0xcc42299e_a1b28468_7e5aad4a_70b749c4_u128,
917 },
918 DyadicFloat128 {
919 sign: DyadicSign::Neg,
920 exponent: -122,
921 mantissa: 0xabb4209d_ca11bdaa_186bef7f_390e6b77_u128,
922 },
923 DyadicFloat128 {
924 sign: DyadicSign::Pos,
925 exponent: -116,
926 mantissa: 0x8a2725e2_4749db25_625ad1f2_12a2a16c_u128,
927 },
928 DyadicFloat128 {
929 sign: DyadicSign::Neg,
930 exponent: -111,
931 mantissa: 0x8b4c2cd4_9e5d0c8b_c9be4d3e_781bb676_u128,
932 },
933 DyadicFloat128 {
934 sign: DyadicSign::Pos,
935 exponent: -107,
936 mantissa: 0xc33fad7c_40599f7d_713e3081_6b5ad791_u128,
937 },
938 DyadicFloat128 {
939 sign: DyadicSign::Neg,
940 exponent: -103,
941 mantissa: 0xc81da271_b623ba88_0be032b5_827d92fa_u128,
942 },
943 DyadicFloat128 {
944 sign: DyadicSign::Pos,
945 exponent: -99,
946 mantissa: 0x99ec4975_b6aa7cae_7692a287_ed8ae47c_u128,
947 },
948 DyadicFloat128 {
949 sign: DyadicSign::Neg,
950 exponent: -96,
951 mantissa: 0xb3aa4745_fc2dd441_2dbd3e3c_d4539687_u128,
952 },
953 DyadicFloat128 {
954 sign: DyadicSign::Pos,
955 exponent: -93,
956 mantissa: 0x9f14edc2_6882afca_29d2a067_dc459729_u128,
957 },
958 DyadicFloat128 {
959 sign: DyadicSign::Neg,
960 exponent: -91,
961 mantissa: 0xd35c4d01_78d8cec6_fc8ae0ee_834da837_u128,
962 },
963 DyadicFloat128 {
964 sign: DyadicSign::Pos,
965 exponent: -89,
966 mantissa: 0xcdc529c7_6e082342_faad3073_07a9b61f_u128,
967 },
968 DyadicFloat128 {
969 sign: DyadicSign::Neg,
970 exponent: -87,
971 mantissa: 0x8ccac88f_2598c8a6_423b1f42_63591cb9_u128,
972 },
973 DyadicFloat128 {
974 sign: DyadicSign::Pos,
975 exponent: -87,
976 mantissa: 0xfc044cfb_a20f0885_93d58660_17819ed5_u128,
977 },
978 DyadicFloat128 {
979 sign: DyadicSign::Neg,
980 exponent: -86,
981 mantissa: 0x813a700c_74d23f52_f81b179d_7ff0da9f_u128,
982 },
983 DyadicFloat128 {
984 sign: DyadicSign::Pos,
985 exponent: -88,
986 mantissa: 0xe6c43da4_297216bf_bdd987cb_636906cf_u128,
987 },
988 DyadicFloat128 {
989 sign: DyadicSign::Neg,
990 exponent: -91,
991 mantissa: 0xa4998323_649c3cf2_64477869_3d2c6afd_u128,
992 },
993 ];
994 static Q: [DyadicFloat128; 16] = [
995 DyadicFloat128 {
996 sign: DyadicSign::Pos,
997 exponent: -127,
998 mantissa: 0x80000000_00000000_00000000_00000000_u128,
999 },
1000 DyadicFloat128 {
1001 sign: DyadicSign::Neg,
1002 exponent: -121,
1003 mantissa: 0xd772d5fd_a7077638_6e007274_d83b013c_u128,
1004 },
1005 DyadicFloat128 {
1006 sign: DyadicSign::Pos,
1007 exponent: -115,
1008 mantissa: 0xad914ef0_451ced2e_515657ef_fc7eeb53_u128,
1009 },
1010 DyadicFloat128 {
1011 sign: DyadicSign::Neg,
1012 exponent: -110,
1013 mantissa: 0xaf41180c_dffe96e5_f192fa40_0b1bff1e_u128,
1014 },
1015 DyadicFloat128 {
1016 sign: DyadicSign::Pos,
1017 exponent: -106,
1018 mantissa: 0xf60dc728_241f71fd_5b93e653_ccbedace_u128,
1019 },
1020 DyadicFloat128 {
1021 sign: DyadicSign::Neg,
1022 exponent: -102,
1023 mantissa: 0xfcaefef9_39cf96e7_3cb75a98_da5e9761_u128,
1024 },
1025 DyadicFloat128 {
1026 sign: DyadicSign::Pos,
1027 exponent: -98,
1028 mantissa: 0xc2d2c837_5789587a_13ef38c6_a24c3413_u128,
1029 },
1030 DyadicFloat128 {
1031 sign: DyadicSign::Neg,
1032 exponent: -95,
1033 mantissa: 0xe41725c3_51d14486_a650044e_e8588f7b_u128,
1034 },
1035 DyadicFloat128 {
1036 sign: DyadicSign::Pos,
1037 exponent: -92,
1038 mantissa: 0xcabeed9b_5e2e888d_81d32b11_d289a624_u128,
1039 },
1040 DyadicFloat128 {
1041 sign: DyadicSign::Neg,
1042 exponent: -89,
1043 mantissa: 0x8764876d_11ad6607_8a8d5382_3ffe82d9_u128,
1044 },
1045 DyadicFloat128 {
1046 sign: DyadicSign::Pos,
1047 exponent: -87,
1048 mantissa: 0x84c9f9e5_6a5f5034_ad2c8512_16cb1ba1_u128,
1049 },
1050 DyadicFloat128 {
1051 sign: DyadicSign::Neg,
1052 exponent: -86,
1053 mantissa: 0xb7c1d143_a15d8aab_03a7fa3e_b7d07a36_u128,
1054 },
1055 DyadicFloat128 {
1056 sign: DyadicSign::Pos,
1057 exponent: -85,
1058 mantissa: 0xa78f8257_4658040f_7a1ad39c_91ea9483_u128,
1059 },
1060 DyadicFloat128 {
1061 sign: DyadicSign::Neg,
1062 exponent: -85,
1063 mantissa: 0xb231e0ca_b729a404_44c38f52_be208507_u128,
1064 },
1065 DyadicFloat128 {
1066 sign: DyadicSign::Pos,
1067 exponent: -86,
1068 mantissa: 0xae317981_42349081_8bc68b28_f69b8e49_u128,
1069 },
1070 DyadicFloat128 {
1071 sign: DyadicSign::Neg,
1072 exponent: -89,
1073 mantissa: 0xb451abd3_5cd79c6d_7e578164_32f16da1_u128,
1074 },
1075 ];
1076
1077 let recip = DyadicFloat128::accurate_reciprocal(x);
1078
1079 let mut p_num = P[15];
1080 for i in (0..15).rev() {
1081 p_num = recip * p_num + P[i];
1082 }
1083
1084 let mut p_den = Q[15];
1085 for i in (0..15).rev() {
1086 p_den = recip * p_den + Q[i];
1087 }
1088
1089 let z = p_num * p_den.reciprocal();
1090
1091 let r_sqrt = bessel_rsqrt_hard(x, recip);
1092 let f_exp = rational128_exp(x);
1093 (z * r_sqrt * f_exp).fast_as_f64()
1094}
1095
1096#[cfg(test)]
1097mod tests {
1098 use super::*;
1099
1100 #[test]
1101 fn test_i0() {
1102 assert_eq!(f_i0(2.2204460492503131e-24f64), 1.0);
1103 assert_eq!(f_i0(f64::EPSILON), 1.0);
1104 assert_eq!(f_i0(9.500000000005492,), 1753.4809905364318);
1105 assert!(f_i0(f64::NAN).is_nan());
1106 assert_eq!(f_i0(f64::INFINITY), f64::INFINITY);
1107 assert_eq!(f_i0(f64::NEG_INFINITY), f64::INFINITY);
1108 assert_eq!(f_i0(7.500000000788034), 268.1613117118702);
1109 assert_eq!(f_i0(715.), f64::INFINITY);
1110 assert_eq!(f_i0(12.), 18948.925349296307);
1111 assert_eq!(f_i0(16.), 893446.227920105);
1112 assert_eq!(f_i0(18.432), 9463892.87209841);
1113 assert_eq!(f_i0(26.432), 23507752424.350075);
1114 assert_eq!(f_i0(0.2), 1.010025027795146);
1115 assert_eq!(f_i0(7.5), 268.16131151518937);
1116 assert_eq!(f_i0(-1.5), 1.646723189772891);
1117 }
1118}