Coverage Report

Created: 2025-11-05 08:08

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/alpha1.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
Note expansion generation below: this is negative series expressed in Sage as positive,
35
so before any real evaluation `x=1/x` should be applied.
36
37
Generated by SageMath:
38
```python
39
def binomial_like(n, m):
40
    prod = QQ(1)
41
    z = QQ(4)*(n**2)
42
    for k in range(1,m + 1):
43
        prod *= (z - (2*k - 1)**2)
44
    return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))
45
46
R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)
47
x = R.gen()
48
49
def Pn_asymptotic(n, y, terms=10):
50
    # now y = 1/x
51
    return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )
52
53
def Qn_asymptotic(n, y, terms=10):
54
    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) )
55
56
P = Pn_asymptotic(1, x, 50)
57
Q = Qn_asymptotic(1, x, 50)
58
59
R_series = (-Q/P)
60
61
# alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series
62
63
arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])
64
alpha_series = arctan_series_Z(R_series)
65
66
# see the series
67
print(alpha_series)
68
```
69
70
See notes/bessel_asympt.ipynb for generation
71
**/
72
#[inline]
73
0
pub(crate) fn bessel_1_asympt_alpha_fast(recip: DoubleDouble) -> DoubleDouble {
74
    const C: [u64; 12] = [
75
        0xbfd8000000000000,
76
        0x3fc5000000000000,
77
        0xbfd7bccccccccccd,
78
        0x4002f486db6db6db,
79
        0xc03e9fbf40000000,
80
        0x4084997b55945d17,
81
        0xc0d4a914195269d9,
82
        0x412cd1b53816aec1,
83
        0xc18aa4095d419351,
84
        0x41ef809305f11b9d,
85
        0xc2572e6809ed618b,
86
        0x42c4c5b6057839f9,
87
    ];
88
89
    // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow
90
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
91
92
0
    let p = f_polyeval9(
93
0
        x2.hi,
94
0
        f64::from_bits(C[3]),
95
0
        f64::from_bits(C[4]),
96
0
        f64::from_bits(C[5]),
97
0
        f64::from_bits(C[6]),
98
0
        f64::from_bits(C[7]),
99
0
        f64::from_bits(C[8]),
100
0
        f64::from_bits(C[9]),
101
0
        f64::from_bits(C[10]),
102
0
        f64::from_bits(C[11]),
103
    );
104
105
0
    let mut z = DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[2]));
106
0
    z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[1]));
107
0
    z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[0]));
108
0
    DoubleDouble::quick_mult(z, recip)
109
0
}
110
111
/**
112
Note expansion generation below: this is negative series expressed in Sage as positive,
113
so before any real evaluation `x=1/x` should be applied.
114
115
Generated by SageMath:
116
```python
117
def binomial_like(n, m):
118
    prod = QQ(1)
119
    z = QQ(4)*(n**2)
120
    for k in range(1,m + 1):
121
        prod *= (z - (2*k - 1)**2)
122
    return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))
123
124
R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)
125
x = R.gen()
126
127
def Pn_asymptotic(n, y, terms=10):
128
    # now y = 1/x
129
    return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )
130
131
def Qn_asymptotic(n, y, terms=10):
132
    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) )
133
134
P = Pn_asymptotic(1, x, 50)
135
Q = Qn_asymptotic(1, x, 50)
136
137
R_series = (-Q/P)
138
139
# alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series
140
141
arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])
142
alpha_series = arctan_series_Z(R_series)
143
144
# see the series
145
print(alpha_series)
146
```
147
148
See notes/bessel_asympt.ipynb for generation
149
**/
150
#[inline]
151
0
pub(crate) fn bessel_1_asympt_alpha(recip: DoubleDouble) -> DoubleDouble {
152
    const C: [(u64, u64); 12] = [
153
        (0x0000000000000000, 0xbfd8000000000000),
154
        (0x0000000000000000, 0x3fc5000000000000),
155
        (0x3c6999999999999a, 0xbfd7bccccccccccd),
156
        (0x3cab6db6db6db6db, 0x4002f486db6db6db),
157
        (0x0000000000000000, 0xc03e9fbf40000000),
158
        (0x3d21745d1745d174, 0x4084997b55945d17),
159
        (0x3d789d89d89d89d9, 0xc0d4a914195269d9),
160
        (0xbdb999999999999a, 0x412cd1b53816aec1),
161
        (0xbdfe5a5a5a5a5a5a, 0xc18aa4095d419351),
162
        (0x3e7e0ca50d79435e, 0x41ef809305f11b9d),
163
        (0xbedff8b720000000, 0xc2572e6809ed618b),
164
        (0xbf64e5d8ae68b7a7, 0x42c4c5b6057839f9),
165
    ];
166
167
    // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow
168
0
    let x2 = DoubleDouble::quick_mult(recip, recip);
169
170
0
    let mut p = DoubleDouble::mul_add(
171
0
        x2,
172
0
        DoubleDouble::from_bit_pair(C[11]),
173
0
        DoubleDouble::from_bit_pair(C[10]),
174
    );
175
176
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[9]));
177
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[8]));
178
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[7]));
179
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[6]));
180
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[5]));
181
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[4]));
182
0
    p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[3].1));
183
0
    p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[2]));
184
0
    p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[1].1));
185
0
    p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1));
186
187
0
    let z = DoubleDouble::quick_mult(p, recip);
188
189
0
    DoubleDouble::from_exact_add(z.hi, z.lo)
190
0
}
191
192
//
193
/// See [bessel_1_asympt_alpha] for the info
194
0
pub(crate) fn bessel_1_asympt_alpha_hard(reciprocal: DyadicFloat128) -> DyadicFloat128 {
195
    static C: [DyadicFloat128; 18] = [
196
        DyadicFloat128 {
197
            sign: DyadicSign::Neg,
198
            exponent: -129,
199
            mantissa: 0xc0000000_00000000_00000000_00000000_u128,
200
        },
201
        DyadicFloat128 {
202
            sign: DyadicSign::Pos,
203
            exponent: -130,
204
            mantissa: 0xa8000000_00000000_00000000_00000000_u128,
205
        },
206
        DyadicFloat128 {
207
            sign: DyadicSign::Neg,
208
            exponent: -129,
209
            mantissa: 0xbde66666_66666666_66666666_66666666_u128,
210
        },
211
        DyadicFloat128 {
212
            sign: DyadicSign::Pos,
213
            exponent: -126,
214
            mantissa: 0x97a436db_6db6db6d_b6db6db6_db6db6db_u128,
215
        },
216
        DyadicFloat128 {
217
            sign: DyadicSign::Neg,
218
            exponent: -123,
219
            mantissa: 0xf4fdfa00_00000000_00000000_00000000_u128,
220
        },
221
        DyadicFloat128 {
222
            sign: DyadicSign::Pos,
223
            exponent: -118,
224
            mantissa: 0xa4cbdaac_a2e8ba2e_8ba2e8ba_2e8ba2e9_u128,
225
        },
226
        DyadicFloat128 {
227
            sign: DyadicSign::Neg,
228
            exponent: -113,
229
            mantissa: 0xa548a0ca_934ec4ec_4ec4ec4e_c4ec4ec5_u128,
230
        },
231
        DyadicFloat128 {
232
            sign: DyadicSign::Pos,
233
            exponent: -108,
234
            mantissa: 0xe68da9c0_b5760666_66666666_66666666_u128,
235
        },
236
        DyadicFloat128 {
237
            sign: DyadicSign::Neg,
238
            exponent: -102,
239
            mantissa: 0xd5204aea_0c9a8879_69696969_69696969_u128,
240
        },
241
        DyadicFloat128 {
242
            sign: DyadicSign::Pos,
243
            exponent: -96,
244
            mantissa: 0xfc04982f_88dce9e0_ca50d794_35e50d79_u128,
245
        },
246
        DyadicFloat128 {
247
            sign: DyadicSign::Neg,
248
            exponent: -89,
249
            mantissa: 0xb973404f_6b0c58ff_c5b90000_00000000_u128,
250
        },
251
        DyadicFloat128 {
252
            sign: DyadicSign::Pos,
253
            exponent: -82,
254
            mantissa: 0xa62db02b_c1cfc563_44ea32e9_0b21642d_u128,
255
        },
256
        DyadicFloat128 {
257
            sign: DyadicSign::Neg,
258
            exponent: -75,
259
            mantissa: 0xb220e7ff_443c1584_7e85f4e0_55eb851f_u128,
260
        },
261
        DyadicFloat128 {
262
            sign: DyadicSign::Pos,
263
            exponent: -68,
264
            mantissa: 0xe10a255c_ca5e68cc_00c2d6c0_acdc8000_u128,
265
        },
266
        DyadicFloat128 {
267
            sign: DyadicSign::Neg,
268
            exponent: -60,
269
            mantissa: 0xa573790c_5186f23b_5db502ea_d9fa5432_u128,
270
        },
271
        DyadicFloat128 {
272
            sign: DyadicSign::Pos,
273
            exponent: -52,
274
            mantissa: 0x8c0ffedc_407a7015_453df84e_9c3f1d39_u128,
275
        },
276
        DyadicFloat128 {
277
            sign: DyadicSign::Neg,
278
            exponent: -44,
279
            mantissa: 0x874226ed_c298a17a_d8c49a4e_dc9281a5_u128,
280
        },
281
        DyadicFloat128 {
282
            sign: DyadicSign::Pos,
283
            exponent: -36,
284
            mantissa: 0x93cab36c_9ab9495c_310fa9cd_4b065359_u128,
285
        },
286
    ];
287
288
0
    let x2 = reciprocal * reciprocal;
289
290
0
    let mut p = C[17];
291
0
    for i in (0..17).rev() {
292
0
        p = x2 * p + C[i];
293
0
    }
294
295
0
    p * reciprocal
296
0
}