Coverage Report

Created: 2025-12-11 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.27/src/bessel/k0.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::double_double::DoubleDouble;
32
use crate::dyadic_float::{DyadicFloat128, DyadicSign};
33
use crate::exponents::rational128_exp;
34
use crate::logs::{fast_log_d_to_dd, log_dd};
35
use crate::polyeval::f_polyeval3;
36
37
/// Modified Bessel of the second kind of order 0
38
///
39
/// Max ULP 0.5
40
0
pub fn f_k0(x: f64) -> f64 {
41
0
    let ix = x.to_bits();
42
43
0
    if ix >= 0x7ffu64 << 52 || ix == 0 {
44
        // |x| == NaN, x == inf, |x| == 0, x < 0
45
0
        if ix.wrapping_shl(1) == 0 {
46
            // |x| == 0
47
0
            return f64::INFINITY;
48
0
        }
49
0
        if x.is_infinite() {
50
0
            return if x.is_sign_positive() { 0. } else { f64::NAN };
51
0
        }
52
0
        return x + f64::NAN; // x == NaN
53
0
    }
54
55
0
    let xb = x.to_bits();
56
57
0
    if xb >= 0x40862e42fefa39f0u64 {
58
        // x >= 709.7827128933841
59
0
        return 0.;
60
0
    }
61
62
0
    if xb <= 0x3ff0000000000000 {
63
        // x <= 1
64
0
        return k0_small_dd(x).to_f64();
65
0
    }
66
67
0
    k0_asympt(x)
68
0
}
69
70
/**
71
Computes I0 on interval [0; 1]
72
as rational approximation I0 = 1 + (x/2)^2 * Pn((x/2)^2)/Qm((x/2)^2))
73
74
Generated by Wolfram Mathematica:
75
```python
76
<<FunctionApproximations`
77
ClearAll["Global`*"]
78
f[x_]:=(BesselI[0,x]-1)/(x/2)^2
79
g[z_]:=f[2 Sqrt[z]]
80
{err,approx}=MiniMaxApproximation[g[z],{z,{0.0000000000001,1},5,5},WorkingPrecision->60]
81
poly=Numerator[approx][[1]];
82
coeffs=CoefficientList[poly,z];
83
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
84
poly=Denominator[approx][[1]];
85
coeffs=CoefficientList[poly,z];
86
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
87
```
88
**/
89
#[inline]
90
0
fn i0_0_to_1_fast(x: f64) -> DoubleDouble {
91
0
    let half_x = x * 0.5; // this is exact
92
0
    let eval_x = DoubleDouble::from_exact_mult(half_x, half_x);
93
94
    const P: [(u64, u64); 3] = [
95
        (0xbae20452afd5045b, 0x3ff0000000000000),
96
        (0xbc5b6ff3f140da20, 0x3fc93c83592c03de),
97
        (0x3c25b350e9128d49, 0x3f904f33ef2de455),
98
    ];
99
100
0
    let ps_num = f_polyeval3(
101
0
        eval_x.hi,
102
0
        f64::from_bits(0x3f433805a2fabaaa),
103
0
        f64::from_bits(0x3ee5897e7f554966),
104
0
        f64::from_bits(0x3e731401f0bb5de4),
105
    );
106
0
    let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[2]));
107
0
    p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1]));
108
0
    p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0]));
109
110
    const Q: [(u64, u64); 3] = [
111
        (0x0000000000000000, 0x3ff0000000000000),
112
        (0x3c323fa63bef2b4e, 0xbfab0df29b4ff089),
113
        (0x3bfedbdf64ed3110, 0x3f564662064157d2),
114
    ];
115
116
0
    let ps_den = f_polyeval3(
117
0
        eval_x.hi,
118
0
        f64::from_bits(0xbef6bdbb484fd0a4),
119
0
        f64::from_bits(0x3e8d6ced53309351),
120
0
        f64::from_bits(0xbe13cff13854e945),
121
    );
122
0
    let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[2]));
123
0
    p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1]));
124
0
    p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0]));
125
0
    let p = DoubleDouble::div(p_num, p_den);
126
127
0
    let z = DoubleDouble::quick_mult(p, eval_x);
128
129
0
    DoubleDouble::full_add_f64(z, 1.)
130
0
}
131
132
/**
133
K0(x) + log(x) * I0(x) = P(x^2)
134
hence
135
K0(x) = P(x^2) - log(x)*I0(x)
136
137
Generated in Wolfram Mathematica:
138
```text
139
<<FunctionApproximations`
140
ClearAll["Global`*"]
141
f[x_]:=BesselK[0,x]+Log[x]BesselI[0,x]
142
g[z_]:=f[Sqrt[z]]
143
{err,approx}=MiniMaxApproximation[g[z],{z,{0.000000001,1},5,5},WorkingPrecision->60]
144
poly=Numerator[approx][[1]];
145
coeffs=CoefficientList[poly,z];
146
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
147
poly=Denominator[approx][[1]];
148
coeffs=CoefficientList[poly,z];
149
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
150
```
151
**/
152
#[inline]
153
0
pub(crate) fn k0_small_dd(x: f64) -> DoubleDouble {
154
0
    let dx = DoubleDouble::from_exact_mult(x, x);
155
    const P: [(u64, u64); 6] = [
156
        (0x3c1be095d044e896, 0x3fbdadb014541eb2),
157
        (0x3c7321baa1d0a2d9, 0x3fd1b9f19bc9019a),
158
        (0xbc33ce33a244e5bd, 0x3f94ec39f8744183),
159
        (0x3bd7008dfc623255, 0x3f3d85175b25727d),
160
        (0xbb4aa2a1c4905d30, 0x3ed007a860ef3235),
161
        (0xbae8daa77abd6f7f, 0x3e4839e32c19f31a),
162
    ];
163
164
0
    let ps_num = f_polyeval3(
165
0
        dx.hi,
166
0
        f64::from_bits(0x3f3d85175b25727d),
167
0
        f64::from_bits(0x3ed007a860ef3235),
168
0
        f64::from_bits(0x3e4839e32c19f31a),
169
    );
170
171
0
    let mut p_num = DoubleDouble::mul_f64_add(dx, ps_num, DoubleDouble::from_bit_pair(P[2]));
172
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[1]));
173
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[0]));
174
175
    const Q: [(u64, u64); 3] = [
176
        (0x0000000000000000, 0x3ff0000000000000),
177
        (0xbc2a82a292acdc83, 0xbf91be3a25c968d6),
178
        (0xbb9d2c37183a6496, 0x3f23bac6961619d8),
179
    ];
180
181
0
    let ps_den = f_polyeval3(
182
0
        dx.hi,
183
0
        f64::from_bits(0xbeac315b81faa1bf),
184
0
        f64::from_bits(0x3e2ab2d2fbae0863),
185
0
        f64::from_bits(0xbd9be23550f83df7),
186
    );
187
0
    let mut p_den = DoubleDouble::mul_f64_add(dx, ps_den, DoubleDouble::from_bit_pair(Q[2]));
188
0
    p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[1]));
189
0
    p_den = DoubleDouble::mul_add_f64(dx, p_den, f64::from_bits(0x3ff0000000000000));
190
191
0
    let prod = DoubleDouble::div(p_num, p_den);
192
193
0
    let vi_log = fast_log_d_to_dd(x);
194
0
    let vi = i0_0_to_1_fast(x);
195
0
    let r = DoubleDouble::mul_add(vi_log, -vi, prod);
196
0
    let err = r.hi * f64::from_bits(0x3c00000000000000); // 2^-63
197
0
    let ub = r.hi + (r.lo + err);
198
0
    let lb = r.hi + (r.lo - err);
199
0
    if ub == lb {
200
0
        return r;
201
0
    }
202
203
0
    k0_small_hard(x, vi)
204
0
}
205
206
/**
207
K0(x) + log(x) * I0(x) = P(x^2)
208
hence
209
K0(x) = P(x^2) - log(x)*I0(x)
210
211
Generated in Wolfram Mathematica:
212
```text
213
<<FunctionApproximations`
214
ClearAll["Global`*"]
215
f[x_]:=BesselK[0,x]+Log[x]BesselI[0,x]
216
g[z_]:=f[Sqrt[z]]
217
{err,approx}=MiniMaxApproximation[g[z],{z,{0.000000001,1},5,5},WorkingPrecision->60]
218
poly=Numerator[approx][[1]];
219
coeffs=CoefficientList[poly,z];
220
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
221
poly=Denominator[approx][[1]];
222
coeffs=CoefficientList[poly,z];
223
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
224
```
225
**/
226
#[cold]
227
#[inline(never)]
228
0
fn k0_small_hard(x: f64, vi: DoubleDouble) -> DoubleDouble {
229
0
    let dx = DoubleDouble::from_exact_mult(x, x);
230
    const P: [(u64, u64); 6] = [
231
        (0x3c1be095d044e896, 0x3fbdadb014541eb2),
232
        (0x3c7321baa1d0a2d9, 0x3fd1b9f19bc9019a),
233
        (0xbc33ce33a244e5bd, 0x3f94ec39f8744183),
234
        (0x3bd7008dfc623255, 0x3f3d85175b25727d),
235
        (0xbb4aa2a1c4905d30, 0x3ed007a860ef3235),
236
        (0xbae8daa77abd6f7f, 0x3e4839e32c19f31a),
237
    ];
238
239
0
    let mut p_num = DoubleDouble::mul_add(
240
0
        dx,
241
0
        DoubleDouble::from_bit_pair(P[5]),
242
0
        DoubleDouble::from_bit_pair(P[4]),
243
    );
244
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[3]));
245
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[2]));
246
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[1]));
247
0
    p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[0]));
248
249
    const Q: [(u64, u64); 6] = [
250
        (0x0000000000000000, 0x3ff0000000000000),
251
        (0xbc2a82a292acdc83, 0xbf91be3a25c968d6),
252
        (0xbb9d2c37183a6496, 0x3f23bac6961619d8),
253
        (0xbb32032e14c6c2b2, 0xbeac315b81faa1bf),
254
        (0x3aa1a1dc04bfba96, 0x3e2ab2d2fbae0863),
255
        (0x3a3e0f678099fcff, 0xbd9be23550f83df7),
256
    ];
257
258
0
    let mut p_den = DoubleDouble::mul_add(
259
0
        dx,
260
0
        DoubleDouble::from_bit_pair(Q[5]),
261
0
        DoubleDouble::from_bit_pair(Q[4]),
262
    );
263
0
    p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[3]));
264
0
    p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[2]));
265
0
    p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[1]));
266
0
    p_den = DoubleDouble::mul_add_f64(dx, p_den, f64::from_bits(0x3ff0000000000000));
267
268
0
    let prod = DoubleDouble::div(p_num, p_den);
269
270
0
    let v_log = log_dd(x);
271
272
0
    DoubleDouble::mul_add(v_log, -vi, prod)
273
0
}
274
275
/**
276
Generated in Wolfram
277
278
Computes sqrt(x)*exp(x)*K0(x)=Pn(1/x)/Qm(1/x)
279
hence
280
K0(x) = Pn(1/x)/Qm(1/x) / (sqrt(x) * exp(x))
281
282
```text
283
<<FunctionApproximations`
284
ClearAll["Global`*"]
285
f[x_]:=Sqrt[x] Exp[x] BesselK[0,x]
286
g[z_]:=f[1/z]
287
{err, approx}=MiniMaxApproximation[g[z],{z,{0.0000000000001,1},11,11},WorkingPrecision->60]
288
poly=Numerator[approx][[1]];
289
coeffs=CoefficientList[poly,z];
290
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
291
poly=Denominator[approx][[1]];
292
coeffs=CoefficientList[poly,z];
293
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
294
```
295
**/
296
#[inline]
297
0
fn k0_asympt(x: f64) -> f64 {
298
0
    let recip = DoubleDouble::from_quick_recip(x);
299
0
    let e = i0_exp(x * 0.5);
300
0
    let r_sqrt = DoubleDouble::from_sqrt(x);
301
302
    const P: [(u64, u64); 12] = [
303
        (0xbc9a6a11d237114e, 0x3ff40d931ff62706),
304
        (0x3cdd614ddf4929e5, 0x4040645168c3e483),
305
        (0xbd1ecf9ea0af6ab2, 0x40757419a703a2ab),
306
        (0xbd3da3551fb27770, 0x409d4e65365522a2),
307
        (0xbd564d58855d1a46, 0x40b6dd32f5a199d9),
308
        (0xbd6cf055ca963a8e, 0x40c4fd2368f19618),
309
        (0x3d4b6cdfbdc058df, 0x40c68faa11ebcd59),
310
        (0x3d5b4ce4665bfa46, 0x40bb6fbe08e0a8ea),
311
        (0xbd4316909063be15, 0x40a1953103a5be31),
312
        (0x3d12f3f8edf41af0, 0x4074d2cb001e175c),
313
        (0xbcd7bba36540264f, 0x40316cffcad5f8f9),
314
        (0xbc6bf28dfdd5d37d, 0x3fc2f487fe78b8d7),
315
    ];
316
317
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
318
0
    let x4 = DoubleDouble::quick_mult(x2, x2);
319
0
    let x8 = DoubleDouble::quick_mult(x4, x4);
320
321
0
    let e0 = DoubleDouble::mul_add(
322
0
        recip,
323
0
        DoubleDouble::from_bit_pair(P[1]),
324
0
        DoubleDouble::from_bit_pair(P[0]),
325
    );
326
0
    let e1 = DoubleDouble::mul_add(
327
0
        recip,
328
0
        DoubleDouble::from_bit_pair(P[3]),
329
0
        DoubleDouble::from_bit_pair(P[2]),
330
    );
331
0
    let e2 = DoubleDouble::mul_add(
332
0
        recip,
333
0
        DoubleDouble::from_bit_pair(P[5]),
334
0
        DoubleDouble::from_bit_pair(P[4]),
335
    );
336
0
    let e3 = DoubleDouble::mul_add(
337
0
        recip,
338
0
        DoubleDouble::from_bit_pair(P[7]),
339
0
        DoubleDouble::from_bit_pair(P[6]),
340
    );
341
0
    let e4 = DoubleDouble::mul_add(
342
0
        recip,
343
0
        DoubleDouble::from_bit_pair(P[9]),
344
0
        DoubleDouble::from_bit_pair(P[8]),
345
    );
346
0
    let e5 = DoubleDouble::mul_add(
347
0
        recip,
348
0
        DoubleDouble::from_bit_pair(P[11]),
349
0
        DoubleDouble::from_bit_pair(P[10]),
350
    );
351
352
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
353
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
354
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
355
356
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
357
358
0
    let p_num = DoubleDouble::mul_add(x8, f2, g0);
359
360
    const Q: [(u64, u64); 12] = [
361
        (0x0000000000000000, 0x3ff0000000000000),
362
        (0xbcb9e8a5b17e696a, 0x403a485acd64d64a),
363
        (0x3cd2e2e9c87f71f7, 0x4071518092320ecb),
364
        (0xbd0d05bdb9431a2f, 0x4097e57e4c22c08e),
365
        (0x3d5207068ab19ba9, 0x40b2ebadb2db62f9),
366
        (0xbd64e37674083471, 0x40c1c0e4e9d6493d),
367
        (0x3d3efb7a9a62b020, 0x40c3b94e8d62cdc7),
368
        (0x3d47d6ce80a2114b, 0x40b93c2fd39e868e),
369
        (0xbd1dfda61f525861, 0x40a1877a53a7f8d8),
370
        (0x3d1236ff523dfcfa, 0x4077c3a10c2827de),
371
        (0xbcc889997c9b0fe7, 0x4039a1d80b11c4a1),
372
        (0x3c7ded0e8d73dddc, 0x3fdafe4913722123),
373
    ];
374
375
0
    let e0 = DoubleDouble::mul_add_f64(
376
0
        recip,
377
0
        DoubleDouble::from_bit_pair(Q[1]),
378
0
        f64::from_bits(0x3ff0000000000000),
379
    );
380
0
    let e1 = DoubleDouble::mul_add(
381
0
        recip,
382
0
        DoubleDouble::from_bit_pair(Q[3]),
383
0
        DoubleDouble::from_bit_pair(Q[2]),
384
    );
385
0
    let e2 = DoubleDouble::mul_add(
386
0
        recip,
387
0
        DoubleDouble::from_bit_pair(Q[5]),
388
0
        DoubleDouble::from_bit_pair(Q[4]),
389
    );
390
0
    let e3 = DoubleDouble::mul_add(
391
0
        recip,
392
0
        DoubleDouble::from_bit_pair(Q[7]),
393
0
        DoubleDouble::from_bit_pair(Q[6]),
394
    );
395
0
    let e4 = DoubleDouble::mul_add(
396
0
        recip,
397
0
        DoubleDouble::from_bit_pair(Q[9]),
398
0
        DoubleDouble::from_bit_pair(Q[8]),
399
    );
400
0
    let e5 = DoubleDouble::mul_add(
401
0
        recip,
402
0
        DoubleDouble::from_bit_pair(Q[11]),
403
0
        DoubleDouble::from_bit_pair(Q[10]),
404
    );
405
406
0
    let f0 = DoubleDouble::mul_add(x2, e1, e0);
407
0
    let f1 = DoubleDouble::mul_add(x2, e3, e2);
408
0
    let f2 = DoubleDouble::mul_add(x2, e5, e4);
409
410
0
    let g0 = DoubleDouble::mul_add(x4, f1, f0);
411
412
0
    let p_den = DoubleDouble::mul_add(x8, f2, g0);
413
414
0
    let z = DoubleDouble::div(p_num, p_den);
415
416
0
    let r = DoubleDouble::div(z, e * r_sqrt * e);
417
418
0
    let err = r.hi * f64::from_bits(0x3c10000000000000); // 2^-62
419
0
    let ub = r.hi + (r.lo + err);
420
0
    let lb = r.hi + (r.lo - err);
421
0
    if ub != lb {
422
0
        return k0_asympt_hard(x);
423
0
    }
424
0
    r.to_f64()
425
0
}
426
427
/**
428
Generated in Wolfram
429
430
Computes sqrt(x)*exp(x)*K0(x)=Pn(1/x)/Qm(1/x)
431
hence
432
K0(x) = Pn(1/x)/Qm(1/x) / (sqrt(x) * exp(x))
433
434
```text
435
<<FunctionApproximations`
436
ClearAll["Global`*"]
437
f[x_]:=Sqrt[x] Exp[x] BesselK[0,x]
438
g[z_]:=f[1/z]
439
{err, approx}=MiniMaxApproximation[g[z],{z,{0.0000000000001,1},14,14},WorkingPrecision->90]
440
poly=Numerator[approx][[1]];
441
coeffs=CoefficientList[poly,z];
442
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
443
poly=Denominator[approx][[1]];
444
coeffs=CoefficientList[poly,z];
445
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
446
```
447
**/
448
#[inline(never)]
449
#[cold]
450
0
fn k0_asympt_hard(x: f64) -> f64 {
451
    static P: [DyadicFloat128; 15] = [
452
        DyadicFloat128 {
453
            sign: DyadicSign::Pos,
454
            exponent: -127,
455
            mantissa: 0xa06c98ff_b1382cb2_be520f51_a7b8f970_u128,
456
        },
457
        DyadicFloat128 {
458
            sign: DyadicSign::Pos,
459
            exponent: -122,
460
            mantissa: 0xc84d8d0c_7faeef84_e56abccc_3d70f8a2_u128,
461
        },
462
        DyadicFloat128 {
463
            sign: DyadicSign::Pos,
464
            exponent: -118,
465
            mantissa: 0xd1a71096_3da22280_35768c9e_0d3ddf42_u128,
466
        },
467
        DyadicFloat128 {
468
            sign: DyadicSign::Pos,
469
            exponent: -115,
470
            mantissa: 0xf202e474_3698aabb_05688da0_ea1a088d_u128,
471
        },
472
        DyadicFloat128 {
473
            sign: DyadicSign::Pos,
474
            exponent: -112,
475
            mantissa: 0xaaa01830_8138af4d_1137b2dd_11a216f5_u128,
476
        },
477
        DyadicFloat128 {
478
            sign: DyadicSign::Pos,
479
            exponent: -110,
480
            mantissa: 0x99e0649f_320bca1a_c7adadb3_f5d8498e_u128,
481
        },
482
        DyadicFloat128 {
483
            sign: DyadicSign::Pos,
484
            exponent: -109,
485
            mantissa: 0xb4d81657_de1baf00_918cbc76_c6974e96_u128,
486
        },
487
        DyadicFloat128 {
488
            sign: DyadicSign::Pos,
489
            exponent: -108,
490
            mantissa: 0x8a9a28c8_a61c2c7a_12416d56_51c0b3d3_u128,
491
        },
492
        DyadicFloat128 {
493
            sign: DyadicSign::Pos,
494
            exponent: -108,
495
            mantissa: 0x88a079f1_d9bd4582_6353316c_3aeb9dc9_u128,
496
        },
497
        DyadicFloat128 {
498
            sign: DyadicSign::Pos,
499
            exponent: -109,
500
            mantissa: 0xa82e10eb_9dc6225a_ef6223e7_54aa254d_u128,
501
        },
502
        DyadicFloat128 {
503
            sign: DyadicSign::Pos,
504
            exponent: -111,
505
            mantissa: 0xf5fc07fe_6b652e8a_0b9e74ba_d0c56118_u128,
506
        },
507
        DyadicFloat128 {
508
            sign: DyadicSign::Pos,
509
            exponent: -113,
510
            mantissa: 0xc5288444_c7354b24_4a4e1663_86488928_u128,
511
        },
512
        DyadicFloat128 {
513
            sign: DyadicSign::Pos,
514
            exponent: -116,
515
            mantissa: 0x96d3d226_a220ae6e_d6cca1ae_40f01e27_u128,
516
        },
517
        DyadicFloat128 {
518
            sign: DyadicSign::Pos,
519
            exponent: -121,
520
            mantissa: 0xa7ab931b_499c4964_499c1091_4ab9673d_u128,
521
        },
522
        DyadicFloat128 {
523
            sign: DyadicSign::Pos,
524
            exponent: -129,
525
            mantissa: 0xf8373d1a_9ff3f9c6_e5cfbe0a_85ccc131_u128,
526
        },
527
    ];
528
529
    static Q: [DyadicFloat128; 15] = [
530
        DyadicFloat128 {
531
            sign: DyadicSign::Pos,
532
            exponent: -127,
533
            mantissa: 0x80000000_00000000_00000000_00000000_u128,
534
        },
535
        DyadicFloat128 {
536
            sign: DyadicSign::Pos,
537
            exponent: -122,
538
            mantissa: 0xa05190f4_dcf0d35c_277e0f21_0635c538_u128,
539
        },
540
        DyadicFloat128 {
541
            sign: DyadicSign::Pos,
542
            exponent: -118,
543
            mantissa: 0xa8837381_94c38992_86c0995d_5e5fa474_u128,
544
        },
545
        DyadicFloat128 {
546
            sign: DyadicSign::Pos,
547
            exponent: -115,
548
            mantissa: 0xc3a4f279_9297e905_f59cc065_75959de8_u128,
549
        },
550
        DyadicFloat128 {
551
            sign: DyadicSign::Pos,
552
            exponent: -112,
553
            mantissa: 0x8b05ade4_03432e06_881ce37d_a907216d_u128,
554
        },
555
        DyadicFloat128 {
556
            sign: DyadicSign::Pos,
557
            exponent: -111,
558
            mantissa: 0xfd77f85e_35626f21_355ae728_01b78cbe_u128,
559
        },
560
        DyadicFloat128 {
561
            sign: DyadicSign::Pos,
562
            exponent: -109,
563
            mantissa: 0x972ed117_254970eb_661121dc_a4462d2f_u128,
564
        },
565
        DyadicFloat128 {
566
            sign: DyadicSign::Pos,
567
            exponent: -109,
568
            mantissa: 0xec9d204a_9294ab57_2ef500d5_59d701b7_u128,
569
        },
570
        DyadicFloat128 {
571
            sign: DyadicSign::Pos,
572
            exponent: -109,
573
            mantissa: 0xf033522d_cae45860_53a01453_c56da895_u128,
574
        },
575
        DyadicFloat128 {
576
            sign: DyadicSign::Pos,
577
            exponent: -109,
578
            mantissa: 0x9a33640c_9896ead5_1ce040d7_b36544f3_u128,
579
        },
580
        DyadicFloat128 {
581
            sign: DyadicSign::Pos,
582
            exponent: -111,
583
            mantissa: 0xefe714fa_49da0166_fdf8bc68_57b77fa0_u128,
584
        },
585
        DyadicFloat128 {
586
            sign: DyadicSign::Pos,
587
            exponent: -113,
588
            mantissa: 0xd323b84c_214196b0_e25b8931_930fea0d_u128,
589
        },
590
        DyadicFloat128 {
591
            sign: DyadicSign::Pos,
592
            exponent: -116,
593
            mantissa: 0xbbb5240b_346642d8_010383cb_1e8a607e_u128,
594
        },
595
        DyadicFloat128 {
596
            sign: DyadicSign::Pos,
597
            exponent: -120,
598
            mantissa: 0x88dcfa2a_f9f7d2ab_dd017994_8fae7e87_u128,
599
        },
600
        DyadicFloat128 {
601
            sign: DyadicSign::Pos,
602
            exponent: -127,
603
            mantissa: 0xc891477c_526e0f5e_74c4ae9f_9d8732b5_u128,
604
        },
605
    ];
606
607
0
    let recip = DyadicFloat128::accurate_reciprocal(x);
608
0
    let e = rational128_exp(x);
609
0
    let r_sqrt = bessel_rsqrt_hard(x, recip);
610
611
0
    let mut p0 = P[14];
612
0
    for i in (0..14).rev() {
613
0
        p0 = recip * p0 + P[i];
614
0
    }
615
616
0
    let mut q = Q[14];
617
0
    for i in (0..14).rev() {
618
0
        q = recip * q + Q[i];
619
0
    }
620
621
0
    let v = p0 * q.reciprocal();
622
0
    let r = v * e.reciprocal() * r_sqrt;
623
0
    r.fast_as_f64()
624
0
}
625
626
#[cfg(test)]
627
mod tests {
628
    use super::*;
629
630
    #[test]
631
    fn test_k0() {
632
        assert_eq!(f_k0(0.11), 2.3332678776741127);
633
        assert_eq!(f_k0(0.643), 0.7241025575342853);
634
        assert_eq!(f_k0(0.964), 0.4433737413379138);
635
        assert_eq!(f_k0(2.964), 0.03621679838808167);
636
        assert_eq!(f_k0(423.43), 7.784461905543397e-186);
637
        assert_eq!(f_k0(0.), f64::INFINITY);
638
        assert_eq!(f_k0(-0.), f64::INFINITY);
639
        assert!(f_k0(-0.5).is_nan());
640
        assert!(f_k0(f64::NEG_INFINITY).is_nan());
641
        assert_eq!(f_k0(f64::INFINITY), 0.);
642
    }
643
}