Coverage Report

Created: 2025-10-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.25/src/bessel/i2.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 8/2025. All rights reserved.
3
 * //
4
 * // Redistribution and use in source and binary forms, with or without modification,
5
 * // are permitted provided that the following conditions are met:
6
 * //
7
 * // 1.  Redistributions of source code must retain the above copyright notice, this
8
 * // list of conditions and the following disclaimer.
9
 * //
10
 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11
 * // this list of conditions and the following disclaimer in the documentation
12
 * // and/or other materials provided with the distribution.
13
 * //
14
 * // 3.  Neither the name of the copyright holder nor the names of its
15
 * // contributors may be used to endorse or promote products derived from
16
 * // this software without specific prior written permission.
17
 * //
18
 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
use crate::bessel::i0::bessel_rsqrt_hard;
30
use crate::bessel::i0_exp;
31
use crate::common::f_fmla;
32
use crate::double_double::DoubleDouble;
33
use crate::dyadic_float::{DyadicFloat128, DyadicSign};
34
use crate::exponents::rational128_exp;
35
36
/// Modified bessel of the first kind of order 2
37
0
pub fn f_i2(x: f64) -> f64 {
38
0
    let ux = x.to_bits().wrapping_shl(1);
39
40
0
    if ux >= 0x7ffu64 << 53 || ux == 0 {
41
        // |x| == 0, |x| == inf, x == NaN
42
0
        if ux == 0 {
43
            // |x| == 0
44
0
            return 0.;
45
0
        }
46
0
        if x.is_infinite() {
47
0
            return f64::INFINITY;
48
0
        }
49
0
        return x + f64::NAN; // x = NaN
50
0
    }
51
52
0
    let xb = x.to_bits() & 0x7fff_ffff_ffff_ffffu64;
53
54
0
    if xb < 0x401f000000000000u64 {
55
        // |x| < 7.75
56
0
        if xb <= 0x3cb0000000000000u64 {
57
            // |x| <= f64::EPSILON
58
            // Power series of I2(x) ~ x^2/8 + O(x^4)
59
            const R: f64 = 1. / 8.;
60
0
            let x2 = x * x * R;
61
0
            return x2;
62
0
        }
63
0
        return i2_small(f64::from_bits(xb));
64
0
    }
65
66
0
    if xb >= 0x40864feaeefb23b8 {
67
        // x >= 713.9897136326099
68
0
        return f64::INFINITY;
69
0
    }
70
71
0
    i2_asympt(f64::from_bits(xb))
72
0
}
73
74
/**
75
Computes
76
I2(x) = x^2 * R(x^2)
77
78
Generated by Wolfram Mathematica:
79
80
```text
81
<<FunctionApproximations`
82
ClearAll["Global`*"]
83
f[x_]:=BesselI[2,x]/x^2
84
g[z_]:=f[Sqrt[z]]
85
{err,approx}=MiniMaxApproximation[g[z],{z,{0.000000000001,7.75},11,11},WorkingPrecision->75]
86
poly=Numerator[approx][[1]];
87
coeffs=CoefficientList[poly,z];
88
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
89
poly=Denominator[approx][[1]];
90
coeffs=CoefficientList[poly,z];
91
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
92
```
93
**/
94
#[inline]
95
0
fn i2_small(x: f64) -> f64 {
96
    const P: [(u64, u64); 12] = [
97
        (0x0000000000000000, 0x3fc0000000000000),
98
        (0x3c247833fda9de9a, 0x3f8387c6e72a1b5f),
99
        (0xbbccaf0be91261a6, 0x3f30ba88efff56fa),
100
        (0x3b57c911bfebe1d7, 0x3ecc62e53d061300),
101
        (0x3af3b963f26a3d05, 0x3e5bb090327a14e1),
102
        (0x3a898bff9d40e030, 0x3de0d29c3d37e5b5),
103
        (0xb9f2f63c80d377db, 0x3d5a9e365f1bf6e0),
104
        (0xb965e6d78e1c2b65, 0x3ccbf7ef0929b813),
105
        (0xb8da83d7d40e7310, 0x3c33737520046f4d),
106
        (0xb83f811d5aa3f36e, 0x3b91506558dab318),
107
        (0xb78e601bf5c998c3, 0x3ae2013b3e858bd1),
108
        (0xb6c8185c51734ed8, 0x3a20cc277a5051ba),
109
    ];
110
0
    let x_sqr = DoubleDouble::from_exact_mult(x, x);
111
0
    let x2 = x_sqr * x_sqr;
112
0
    let x4 = x2 * x2;
113
0
    let x8 = x4 * x4;
114
115
0
    let e0 = DoubleDouble::mul_add_f64(
116
0
        x_sqr,
117
0
        DoubleDouble::from_bit_pair(P[1]),
118
0
        f64::from_bits(0x3fc0000000000000),
119
    );
120
0
    let e1 = DoubleDouble::mul_add(
121
0
        x_sqr,
122
0
        DoubleDouble::from_bit_pair(P[3]),
123
0
        DoubleDouble::from_bit_pair(P[2]),
124
    );
125
0
    let e2 = DoubleDouble::mul_add(
126
0
        x_sqr,
127
0
        DoubleDouble::from_bit_pair(P[5]),
128
0
        DoubleDouble::from_bit_pair(P[4]),
129
    );
130
0
    let e3 = DoubleDouble::mul_add(
131
0
        x_sqr,
132
0
        DoubleDouble::from_bit_pair(P[7]),
133
0
        DoubleDouble::from_bit_pair(P[6]),
134
    );
135
0
    let e4 = DoubleDouble::mul_add(
136
0
        x_sqr,
137
0
        DoubleDouble::from_bit_pair(P[9]),
138
0
        DoubleDouble::from_bit_pair(P[8]),
139
    );
140
0
    let e5 = DoubleDouble::mul_add(
141
0
        x_sqr,
142
0
        DoubleDouble::from_bit_pair(P[11]),
143
0
        DoubleDouble::from_bit_pair(P[10]),
144
    );
145
146
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
147
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
148
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
149
150
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
151
152
0
    let p_num = DoubleDouble::mul_add(x8, f2, g0);
153
154
    const Q: [(u64, u64); 12] = [
155
        (0x0000000000000000, 0x3ff0000000000000),
156
        (0xbc0ba42af56ed76b, 0xbf7cd8e6e2b39f60),
157
        (0x3b90697aa005e598, 0x3efa0260394e1a3d),
158
        (0xbb0c7ccde1f63c82, 0xbe6f1766ec64e492),
159
        (0x3a63f18409bc336f, 0x3ddb80b6b5abad98),
160
        (0xb9e0cd49f22132fe, 0xbd42ff9b55d553da),
161
        (0xb934bfe64905d309, 0x3ca50814fa258ebc),
162
        (0x38a1e35c2d6860f4, 0xbc02c4f2faca2195),
163
        (0xb7ff39e268277e4e, 0x3b5aa545a2c1f16d),
164
        (0xb71053f58545760c, 0xbaacde4c133d42d1),
165
        (0xb68d0c2ccab0ae5b, 0x39f5a965b92b06bc),
166
        (0xb5dc35bda16bee7b, 0xb931375b1c9cfbc7),
167
    ];
168
169
0
    let e0 = DoubleDouble::mul_add_f64(
170
0
        x_sqr,
171
0
        DoubleDouble::from_bit_pair(Q[1]),
172
0
        f64::from_bits(0x3ff0000000000000),
173
    );
174
0
    let e1 = DoubleDouble::mul_add(
175
0
        x_sqr,
176
0
        DoubleDouble::from_bit_pair(Q[3]),
177
0
        DoubleDouble::from_bit_pair(Q[2]),
178
    );
179
0
    let e2 = DoubleDouble::mul_add(
180
0
        x_sqr,
181
0
        DoubleDouble::from_bit_pair(Q[5]),
182
0
        DoubleDouble::from_bit_pair(Q[4]),
183
    );
184
0
    let e3 = DoubleDouble::mul_add(
185
0
        x_sqr,
186
0
        DoubleDouble::from_bit_pair(Q[7]),
187
0
        DoubleDouble::from_bit_pair(Q[6]),
188
    );
189
0
    let e4 = DoubleDouble::mul_add(
190
0
        x_sqr,
191
0
        DoubleDouble::from_bit_pair(Q[9]),
192
0
        DoubleDouble::from_bit_pair(Q[8]),
193
    );
194
0
    let e5 = DoubleDouble::mul_add(
195
0
        x_sqr,
196
0
        DoubleDouble::from_bit_pair(Q[11]),
197
0
        DoubleDouble::from_bit_pair(Q[10]),
198
    );
199
200
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
201
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
202
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
203
204
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
205
206
0
    let p_den = DoubleDouble::mul_add(x8, f2, g0);
207
208
0
    let p = DoubleDouble::div(p_num, p_den);
209
0
    DoubleDouble::quick_mult(p, x_sqr).to_f64()
210
0
}
211
212
/**
213
Asymptotic expansion for I2.
214
I2(x)=R(1/x)*Exp(x)/sqrt(x)
215
216
Generated in Wolfram:
217
```text
218
<<FunctionApproximations`
219
ClearAll["Global`*"]
220
f[x_]:=Sqrt[x] Exp[-x] BesselI[2,x]
221
g[z_]:=f[1/z]
222
{err,approx}=MiniMaxApproximation[g[z],{z,{1/714.0,1/7.5},11,11},WorkingPrecision->120]
223
poly=Numerator[approx][[1]];
224
coeffs=CoefficientList[poly,z];
225
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
226
poly=Denominator[approx][[1]];
227
coeffs=CoefficientList[poly,z];
228
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
229
```
230
**/
231
#[inline]
232
0
fn i2_asympt(x: f64) -> f64 {
233
0
    let dx = x;
234
0
    let recip = DoubleDouble::from_quick_recip(x);
235
    const P: [(u64, u64); 12] = [
236
        (0x3c718bb28ebc5f4e, 0x3fd9884533d43650),
237
        (0x3c96e15a87b6e1d1, 0xc0350acc9e5cb0f9),
238
        (0xbd20b212a79e08f5, 0x40809251af67598a),
239
        (0xbd563b7397df3a54, 0xc0bfc09ede682c8b),
240
        (0xbd5eb872cb057d91, 0x40f44253a9e1e1ab),
241
        (0x3d7614735e566fc5, 0xc121cbcd96dc8765),
242
        (0xbddc4f8df2010026, 0x4145a592e8ec74ad),
243
        (0x3dea227617b678a7, 0xc161df96fb6a9df9),
244
        (0x3e17c9690d906194, 0x41732c71397757f8),
245
        (0x3e0638226ce0b938, 0xc178893fde0e6ed7),
246
        (0xbe09d8dc4e7930ce, 0x417066abe24b31df),
247
        (0xbde152007ee29e54, 0xc150531da3f31b16),
248
    ];
249
250
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
251
0
    let x4 = DoubleDouble::quick_mult(x2, x2);
252
0
    let x8 = DoubleDouble::quick_mult(x4, x4);
253
254
0
    let e0 = DoubleDouble::mul_add(
255
0
        recip,
256
0
        DoubleDouble::from_bit_pair(P[1]),
257
0
        DoubleDouble::from_bit_pair(P[0]),
258
    );
259
0
    let e1 = DoubleDouble::mul_add(
260
0
        recip,
261
0
        DoubleDouble::from_bit_pair(P[3]),
262
0
        DoubleDouble::from_bit_pair(P[2]),
263
    );
264
0
    let e2 = DoubleDouble::mul_add(
265
0
        recip,
266
0
        DoubleDouble::from_bit_pair(P[5]),
267
0
        DoubleDouble::from_bit_pair(P[4]),
268
    );
269
0
    let e3 = DoubleDouble::mul_add(
270
0
        recip,
271
0
        DoubleDouble::from_bit_pair(P[7]),
272
0
        DoubleDouble::from_bit_pair(P[6]),
273
    );
274
0
    let e4 = DoubleDouble::mul_add(
275
0
        recip,
276
0
        DoubleDouble::from_bit_pair(P[9]),
277
0
        DoubleDouble::from_bit_pair(P[8]),
278
    );
279
0
    let e5 = DoubleDouble::mul_add(
280
0
        recip,
281
0
        DoubleDouble::from_bit_pair(P[11]),
282
0
        DoubleDouble::from_bit_pair(P[10]),
283
    );
284
285
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
286
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
287
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
288
289
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
290
291
0
    let p_num = DoubleDouble::mul_add(x8, f2, g0);
292
293
    const Q: [(u64, u64); 12] = [
294
        (0x0000000000000000, 0x3ff0000000000000),
295
        (0xbcd0d33e9e73b503, 0xc0496f5a09751d50),
296
        (0x3d2f9c44a069dc4b, 0x40934427187ac370),
297
        (0xbd69e2e5a3618381, 0xc0d19983f74fdf52),
298
        (0x3d88c69a62ae8b44, 0x410524fcaa71e85a),
299
        (0xbdc0345b806dd0bf, 0xc13120daf531b66b),
300
        (0xbdd35875712fff6f, 0x4152943a4f9f1c7f),
301
        (0xbdf8dd50e92553fd, 0xc169b83aeede08ea),
302
        (0x3e0800ecaa77f79e, 0x41746c61554a08ce),
303
        (0x3dd74fbc32c5f696, 0xc16ba2febd1932a3),
304
        (0x3dc23eb2c943b539, 0x413574ae68b6b378),
305
        (0xbd95d86c5c94cd65, 0xc104adac99eaa90c),
306
    ];
307
308
0
    let e0 = DoubleDouble::mul_add_f64(
309
0
        recip,
310
0
        DoubleDouble::from_bit_pair(Q[1]),
311
0
        f64::from_bits(0x3ff0000000000000),
312
    );
313
0
    let e1 = DoubleDouble::mul_add(
314
0
        recip,
315
0
        DoubleDouble::from_bit_pair(Q[3]),
316
0
        DoubleDouble::from_bit_pair(Q[2]),
317
    );
318
0
    let e2 = DoubleDouble::mul_add(
319
0
        recip,
320
0
        DoubleDouble::from_bit_pair(Q[5]),
321
0
        DoubleDouble::from_bit_pair(Q[4]),
322
    );
323
0
    let e3 = DoubleDouble::mul_add(
324
0
        recip,
325
0
        DoubleDouble::from_bit_pair(Q[7]),
326
0
        DoubleDouble::from_bit_pair(Q[6]),
327
    );
328
0
    let e4 = DoubleDouble::mul_add(
329
0
        recip,
330
0
        DoubleDouble::from_bit_pair(Q[9]),
331
0
        DoubleDouble::from_bit_pair(Q[8]),
332
    );
333
0
    let e5 = DoubleDouble::mul_add(
334
0
        recip,
335
0
        DoubleDouble::from_bit_pair(Q[11]),
336
0
        DoubleDouble::from_bit_pair(Q[10]),
337
    );
338
339
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
340
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
341
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
342
343
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
344
345
0
    let p_den = DoubleDouble::mul_add(x8, f2, g0);
346
347
0
    let z = DoubleDouble::div(p_num, p_den);
348
349
0
    let mut e = i0_exp(dx * 0.5);
350
0
    e = DoubleDouble::from_exact_add(e.hi, e.lo);
351
0
    let r_sqrt = DoubleDouble::from_rsqrt_fast(dx);
352
0
    let r = DoubleDouble::quick_mult(z * r_sqrt * e, e);
353
0
    let err = f_fmla(
354
0
        r.hi,
355
0
        f64::from_bits(0x3c40000000000000), // 2^-59
356
0
        f64::from_bits(0x3ba0000000000000), // 2^-69
357
    );
358
0
    let up = r.hi + (r.lo + err);
359
0
    let lb = r.hi + (r.lo - err);
360
0
    if up == lb {
361
0
        return r.to_f64();
362
0
    }
363
0
    i2_asympt_hard(x)
364
0
}
365
366
/**
367
Asymptotic expansion for I2.
368
I2(x)=R(1/x)*Exp(x)/sqrt(x)
369
370
Generated in Wolfram:
371
```text
372
<<FunctionApproximations`
373
ClearAll["Global`*"]
374
f[x_]:=Sqrt[x] Exp[-x] BesselI[2,x]
375
g[z_]:=f[1/z]
376
{err,approx}=MiniMaxApproximation[g[z],{z,{1/714.0,1/7.5},15,15},WorkingPrecision->120]
377
poly=Numerator[approx][[1]];
378
coeffs=CoefficientList[poly,z];
379
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
380
poly=Denominator[approx][[1]];
381
coeffs=CoefficientList[poly,z];
382
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
383
```
384
**/
385
#[cold]
386
#[inline(never)]
387
0
fn i2_asympt_hard(x: f64) -> f64 {
388
    static P: [DyadicFloat128; 16] = [
389
        DyadicFloat128 {
390
            sign: DyadicSign::Pos,
391
            exponent: -129,
392
            mantissa: 0xcc42299e_a1b28468_3bb16645_ba1dc793_u128,
393
        },
394
        DyadicFloat128 {
395
            sign: DyadicSign::Neg,
396
            exponent: -123,
397
            mantissa: 0xe202abf7_de10e93f_2a2e6a0f_af69c788_u128,
398
        },
399
        DyadicFloat128 {
400
            sign: DyadicSign::Pos,
401
            exponent: -118,
402
            mantissa: 0xf70296c3_ad33bde6_866cfd01_0e846cfc_u128,
403
        },
404
        DyadicFloat128 {
405
            sign: DyadicSign::Neg,
406
            exponent: -113,
407
            mantissa: 0xa83df971_736c4e6c_1a35479b_ad6d9172_u128,
408
        },
409
        DyadicFloat128 {
410
            sign: DyadicSign::Pos,
411
            exponent: -109,
412
            mantissa: 0x9baa2015_9c5ca461_0aff0b62_54a70fdb_u128,
413
        },
414
        DyadicFloat128 {
415
            sign: DyadicSign::Neg,
416
            exponent: -106,
417
            mantissa: 0xc70af95d_f95d14ad_1094ea1b_e46b2d2f_u128,
418
        },
419
        DyadicFloat128 {
420
            sign: DyadicSign::Pos,
421
            exponent: -103,
422
            mantissa: 0xa838fb48_e79fb706_642da604_6a73b4f8_u128,
423
        },
424
        DyadicFloat128 {
425
            sign: DyadicSign::Neg,
426
            exponent: -101,
427
            mantissa: 0x8fe29f37_02b1e876_39e88664_1c8b3b5d_u128,
428
        },
429
        DyadicFloat128 {
430
            sign: DyadicSign::Neg,
431
            exponent: -100,
432
            mantissa: 0xc8e9a474_0a03f93a_16d2e7a9_627eba4e_u128,
433
        },
434
        DyadicFloat128 {
435
            sign: DyadicSign::Pos,
436
            exponent: -95,
437
            mantissa: 0x8807d1f6_6d646a08_8c7e8900_12d6a5ed_u128,
438
        },
439
        DyadicFloat128 {
440
            sign: DyadicSign::Neg,
441
            exponent: -93,
442
            mantissa: 0xe5c25026_97518024_36878256_fd81c08f_u128,
443
        },
444
        DyadicFloat128 {
445
            sign: DyadicSign::Pos,
446
            exponent: -91,
447
            mantissa: 0xeaa075f0_f5151bed_95ec612f_ab9834a7_u128,
448
        },
449
        DyadicFloat128 {
450
            sign: DyadicSign::Neg,
451
            exponent: -89,
452
            mantissa: 0x9b267222_82d5c666_348d7d1d_0fedfba4_u128,
453
        },
454
        DyadicFloat128 {
455
            sign: DyadicSign::Pos,
456
            exponent: -88,
457
            mantissa: 0x81b45c4c_3e828396_1d5bdede_869c3b84_u128,
458
        },
459
        DyadicFloat128 {
460
            sign: DyadicSign::Neg,
461
            exponent: -89,
462
            mantissa: 0xf4495d43_4bc8dba6_42bdb5d6_c8ba2c9c_u128,
463
        },
464
        DyadicFloat128 {
465
            sign: DyadicSign::Pos,
466
            exponent: -90,
467
            mantissa: 0xc9b29546_0c226270_bb428035_587b6d6a_u128,
468
        },
469
    ];
470
    static Q: [DyadicFloat128; 16] = [
471
        DyadicFloat128 {
472
            sign: DyadicSign::Pos,
473
            exponent: -127,
474
            mantissa: 0x80000000_00000000_00000000_00000000_u128,
475
        },
476
        DyadicFloat128 {
477
            sign: DyadicSign::Neg,
478
            exponent: -121,
479
            mantissa: 0x89e18bae_ca9629a1_26927ba2_fbdd66ab_u128,
480
        },
481
        DyadicFloat128 {
482
            sign: DyadicSign::Pos,
483
            exponent: -116,
484
            mantissa: 0x92a90fc2_e905f634_4946e8a0_dd8e3874_u128,
485
        },
486
        DyadicFloat128 {
487
            sign: DyadicSign::Neg,
488
            exponent: -112,
489
            mantissa: 0xc1742696_d29e3846_3e183737_29db8b68_u128,
490
        },
491
        DyadicFloat128 {
492
            sign: DyadicSign::Pos,
493
            exponent: -108,
494
            mantissa: 0xabf61cc0_236a0e90_2572113d_fa339591_u128,
495
        },
496
        DyadicFloat128 {
497
            sign: DyadicSign::Neg,
498
            exponent: -105,
499
            mantissa: 0xcff0fe90_dac1b08e_9a5740ae_b2984fc1_u128,
500
        },
501
        DyadicFloat128 {
502
            sign: DyadicSign::Pos,
503
            exponent: -102,
504
            mantissa: 0x9ff36729_e407c538_cfcea3a7_63f39043_u128,
505
        },
506
        DyadicFloat128 {
507
            sign: DyadicSign::Neg,
508
            exponent: -101,
509
            mantissa: 0xc86ff6a3_9b803a31_d385e9ea_83f9d751_u128,
510
        },
511
        DyadicFloat128 {
512
            sign: DyadicSign::Neg,
513
            exponent: -98,
514
            mantissa: 0xb4a125b1_6cab70f3_0f314558_708843df_u128,
515
        },
516
        DyadicFloat128 {
517
            sign: DyadicSign::Pos,
518
            exponent: -94,
519
            mantissa: 0x9670fd33_f83bcaa7_85cf2d82_c0bf8cd5_u128,
520
        },
521
        DyadicFloat128 {
522
            sign: DyadicSign::Neg,
523
            exponent: -92,
524
            mantissa: 0xd70b4ea5_32fedb9d_78a3c047_05e650f4_u128,
525
        },
526
        DyadicFloat128 {
527
            sign: DyadicSign::Pos,
528
            exponent: -90,
529
            mantissa: 0xb9c7904c_3f97b633_c2c0ad9b_ad573ede_u128,
530
        },
531
        DyadicFloat128 {
532
            sign: DyadicSign::Neg,
533
            exponent: -89,
534
            mantissa: 0xc2023c21_5155e9fe_6fb17bb2_c865becd_u128,
535
        },
536
        DyadicFloat128 {
537
            sign: DyadicSign::Pos,
538
            exponent: -89,
539
            mantissa: 0xd9400a5e_27c58803_22948cf3_6154ac49_u128,
540
        },
541
        DyadicFloat128 {
542
            sign: DyadicSign::Neg,
543
            exponent: -90,
544
            mantissa: 0x87aa272d_6a9700b4_449a9db8_1a93b0ee_u128,
545
        },
546
        DyadicFloat128 {
547
            sign: DyadicSign::Neg,
548
            exponent: -93,
549
            mantissa: 0xd1a86655_5b259611_dfc7affc_6ffb0e20_u128,
550
        },
551
    ];
552
553
0
    let recip = DyadicFloat128::accurate_reciprocal(x);
554
555
0
    let mut p_num = P[15];
556
0
    for i in (0..15).rev() {
557
0
        p_num = recip * p_num + P[i];
558
0
    }
559
0
    let mut p_den = Q[15];
560
0
    for i in (0..15).rev() {
561
0
        p_den = recip * p_den + Q[i];
562
0
    }
563
0
    let z = p_num * p_den.reciprocal();
564
0
    let r_sqrt = bessel_rsqrt_hard(x, recip);
565
0
    let f_exp = rational128_exp(x);
566
0
    (z * r_sqrt * f_exp).fast_as_f64()
567
0
}
568
569
#[cfg(test)]
570
mod tests {
571
    use super::*;
572
573
    #[test]
574
    fn test_i2() {
575
        assert_eq!(f_i2(7.750000000757874), 257.0034362785801);
576
        assert_eq!(f_i2(7.482812501363189), 198.26765887136534);
577
        assert_eq!(f_i2(-7.750000000757874), 257.0034362785801);
578
        assert_eq!(f_i2(-7.482812501363189), 198.26765887136534);
579
        assert!(f_i2(f64::NAN).is_nan());
580
        assert_eq!(f_i2(f64::INFINITY), f64::INFINITY);
581
        assert_eq!(f_i2(f64::NEG_INFINITY), f64::INFINITY);
582
        assert_eq!(f_i2(0.01), 1.2500104166992188e-5);
583
        assert_eq!(f_i2(-0.01), 1.2500104166992188e-5);
584
        assert_eq!(f_i2(-9.01), 872.9250699638584);
585
        assert_eq!(f_i2(9.01), 872.9250699638584);
586
    }
587
}