Coverage Report

Created: 2026-05-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.29/src/bessel/alpha0.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::double_double::DoubleDouble;
30
use crate::dyadic_float::{DyadicFloat128, DyadicSign};
31
use crate::polyeval::f_polyeval9;
32
33
//
34
/// See [bessel_0_asympt_alpha] for the info
35
0
pub(crate) fn bessel_0_asympt_alpha_hard(reciprocal: DyadicFloat128) -> DyadicFloat128 {
36
    static C: [DyadicFloat128; 18] = [
37
        DyadicFloat128 {
38
            sign: DyadicSign::Pos,
39
            exponent: -130,
40
            mantissa: 0x80000000_00000000_00000000_00000000_u128,
41
        },
42
        DyadicFloat128 {
43
            sign: DyadicSign::Neg,
44
            exponent: -131,
45
            mantissa: 0x85555555_55555555_55555555_55555555_u128,
46
        },
47
        DyadicFloat128 {
48
            sign: DyadicSign::Pos,
49
            exponent: -130,
50
            mantissa: 0xd6999999_99999999_99999999_9999999a_u128,
51
        },
52
        DyadicFloat128 {
53
            sign: DyadicSign::Neg,
54
            exponent: -127,
55
            mantissa: 0xd1ac2492_49249249_24924924_92492492_u128,
56
        },
57
        DyadicFloat128 {
58
            sign: DyadicSign::Pos,
59
            exponent: -123,
60
            mantissa: 0xbbcd0fc7_1c71c71c_71c71c71_c71c71c7_u128,
61
        },
62
        DyadicFloat128 {
63
            sign: DyadicSign::Neg,
64
            exponent: -118,
65
            mantissa: 0x85e8fe45_8ba2e8ba_2e8ba2e8_ba2e8ba3_u128,
66
        },
67
        DyadicFloat128 {
68
            sign: DyadicSign::Pos,
69
            exponent: -113,
70
            mantissa: 0x8b5a8f33_63c4ec4e_c4ec4ec4_ec4ec4ec_u128,
71
        },
72
        DyadicFloat128 {
73
            sign: DyadicSign::Neg,
74
            exponent: -108,
75
            mantissa: 0xc7661d79_9d59b555_55555555_55555555_u128,
76
        },
77
        DyadicFloat128 {
78
            sign: DyadicSign::Pos,
79
            exponent: -102,
80
            mantissa: 0xbbced715_c2897a28_78787878_78787878_u128,
81
        },
82
        DyadicFloat128 {
83
            sign: DyadicSign::Neg,
84
            exponent: -96,
85
            mantissa: 0xe14b19b4_aae3f7fe_be1af286_bca1af28_u128,
86
        },
87
        DyadicFloat128 {
88
            sign: DyadicSign::Pos,
89
            exponent: -89,
90
            mantissa: 0xa7af7341_db2192db_975e0c30_c30c30c3_u128,
91
        },
92
        DyadicFloat128 {
93
            sign: DyadicSign::Neg,
94
            exponent: -82,
95
            mantissa: 0x97a8f676_b349f6fc_5cefd338_590b2164_u128,
96
        },
97
        DyadicFloat128 {
98
            sign: DyadicSign::Pos,
99
            exponent: -75,
100
            mantissa: 0xa3d299fb_6f304d73_86e15f12_0fd70a3d_u128,
101
        },
102
        DyadicFloat128 {
103
            sign: DyadicSign::Neg,
104
            exponent: -68,
105
            mantissa: 0xd050b737_cbc044ef_e8807e3c_87f43da1_u128,
106
        },
107
        DyadicFloat128 {
108
            sign: DyadicSign::Pos,
109
            exponent: -60,
110
            mantissa: 0x9a02379b_daa7e492_854f42de_6d3dffe6_u128,
111
        },
112
        DyadicFloat128 {
113
            sign: DyadicSign::Neg,
114
            exponent: -52,
115
            mantissa: 0x83011a39_380e467d_de6b70ec_b92ce0cc_u128,
116
        },
117
        DyadicFloat128 {
118
            sign: DyadicSign::Pos,
119
            exponent: -45,
120
            mantissa: 0xfe16521f_c79e5d9a_a5bed653_e3844e9a_u128,
121
        },
122
        DyadicFloat128 {
123
            sign: DyadicSign::Neg,
124
            exponent: -36,
125
            mantissa: 0x8b54b13d_3fb3e1c4_15dbb880_0bb32218_u128,
126
        },
127
    ];
128
129
0
    let x2 = reciprocal * reciprocal;
130
131
0
    let mut p = C[17];
132
0
    for i in (0..17).rev() {
133
0
        p = x2 * p + C[i];
134
0
    }
135
136
0
    p * reciprocal
137
0
}
138
139
/**
140
Note expansion generation below: this is negative series expressed in Sage as positive,
141
so before any real evaluation `x=1/x` should be applied.
142
143
Generated by SageMath:
144
```python
145
def binomial_like(n, m):
146
    prod = QQ(1)
147
    z = QQ(4)*(n**2)
148
    for k in range(1,m + 1):
149
        prod *= (z - (2*k - 1)**2)
150
    return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))
151
152
R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)
153
x = R.gen()
154
155
def Pn_asymptotic(n, y, terms=10):
156
    # now y = 1/x
157
    return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )
158
159
def Qn_asymptotic(n, y, terms=10):
160
    return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) )
161
162
P = Pn_asymptotic(0, x, 50)
163
Q = Qn_asymptotic(0, x, 50)
164
165
R_series = (-Q/P)
166
167
# alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series
168
169
arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])
170
alpha_series = arctan_series_Z(R_series)
171
172
# see the series
173
print(alpha_series)
174
```
175
**/
176
#[inline]
177
0
pub(crate) fn bessel_0_asympt_alpha(recip: DoubleDouble) -> DoubleDouble {
178
    const C: [(u64, u64); 12] = [
179
        (0x0000000000000000, 0x3fc0000000000000),
180
        (0x3c55555555555555, 0xbfb0aaaaaaaaaaab),
181
        (0x3c5999999999999a, 0x3fcad33333333333),
182
        (0xbc92492492492492, 0xbffa358492492492),
183
        (0xbcbc71c71c71c71c, 0x403779a1f8e38e39),
184
        (0xbd0745d1745d1746, 0xc080bd1fc8b1745d),
185
        (0xbd7d89d89d89d89e, 0x40d16b51e66c789e),
186
        (0x3dc5555555555555, 0xc128ecc3af33ab37),
187
        (0x3e2143c3c3c3c3c4, 0x418779dae2b8512f),
188
        (0x3df41e50d79435e5, 0xc1ec296336955c7f),
189
        (0x3ef6dcbaf0618618, 0x4254f5ee683b6432),
190
        (0x3f503a3102cc7a6f, 0xc2c2f51eced6693f),
191
    ];
192
193
    // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow
194
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
195
196
0
    let mut p = DoubleDouble::mul_add(
197
0
        x2,
198
0
        DoubleDouble::from_bit_pair(C[11]),
199
0
        DoubleDouble::from_bit_pair(C[10]),
200
    );
201
202
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[9]));
203
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[8]));
204
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[7]));
205
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[6]));
206
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[5]));
207
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[4]));
208
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[3]));
209
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[2]));
210
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[1]));
211
0
    p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1));
212
213
0
    let z = DoubleDouble::quick_mult(p, recip);
214
215
0
    DoubleDouble::from_exact_add(z.hi, z.lo)
216
0
}
217
218
/**
219
Note expansion generation below: this is negative series expressed in Sage as positive,
220
so before any real evaluation `x=1/x` should be applied.
221
222
Generated by SageMath:
223
```python
224
def binomial_like(n, m):
225
    prod = QQ(1)
226
    z = QQ(4)*(n**2)
227
    for k in range(1,m + 1):
228
        prod *= (z - (2*k - 1)**2)
229
    return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))
230
231
R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)
232
x = R.gen()
233
234
def Pn_asymptotic(n, y, terms=10):
235
    # now y = 1/x
236
    return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )
237
238
def Qn_asymptotic(n, y, terms=10):
239
    return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) )
240
241
P = Pn_asymptotic(0, x, 50)
242
Q = Qn_asymptotic(0, x, 50)
243
244
R_series = (-Q/P)
245
246
# alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series
247
248
arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])
249
alpha_series = arctan_series_Z(R_series)
250
251
# see the series
252
print(alpha_series)
253
```
254
**/
255
#[inline]
256
0
pub(crate) fn bessel_0_asympt_alpha_fast(recip: DoubleDouble) -> DoubleDouble {
257
    const C: [u64; 12] = [
258
        0x3fc0000000000000,
259
        0xbfb0aaaaaaaaaaab,
260
        0x3fcad33333333333,
261
        0xbffa358492492492,
262
        0x403779a1f8e38e39,
263
        0xc080bd1fc8b1745d,
264
        0x40d16b51e66c789e,
265
        0xc128ecc3af33ab37,
266
        0x418779dae2b8512f,
267
        0xc1ec296336955c7f,
268
        0x4254f5ee683b6432,
269
        0xc2c2f51eced6693f,
270
    ];
271
272
    // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow
273
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
274
275
0
    let p = f_polyeval9(
276
0
        x2.hi,
277
0
        f64::from_bits(C[3]),
278
0
        f64::from_bits(C[4]),
279
0
        f64::from_bits(C[5]),
280
0
        f64::from_bits(C[6]),
281
0
        f64::from_bits(C[7]),
282
0
        f64::from_bits(C[8]),
283
0
        f64::from_bits(C[9]),
284
0
        f64::from_bits(C[10]),
285
0
        f64::from_bits(C[11]),
286
    );
287
288
0
    let mut z = DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[2]));
289
0
    z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[1]));
290
0
    z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[0]));
291
0
    DoubleDouble::quick_mult(z, recip)
292
0
}