Coverage Report

Created: 2025-12-20 06:48

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/i2f.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::j0f::j1f_rsqrt;
30
use crate::exponents::core_expf;
31
use crate::polyeval::{f_estrin_polyeval8, f_estrin_polyeval9};
32
33
/// Modified Bessel of the first kind of order 2
34
///
35
/// ULP 0.5
36
0
pub fn f_i2f(x: f32) -> f32 {
37
0
    let ux = x.to_bits().wrapping_shl(1);
38
0
    if ux >= 0xffu32 << 24 || ux == 0 {
39
        // |x| == 0, |x| == inf, |x| == NaN
40
0
        if ux == 0 {
41
            // |x| == 0
42
0
            return 0.;
43
0
        }
44
0
        if x.is_infinite() {
45
0
            return f32::INFINITY;
46
0
        }
47
0
        return x + f32::NAN; // x == NaN
48
0
    }
49
50
0
    let xb = x.to_bits() & 0x7fff_ffff;
51
52
0
    if xb >= 0x42b7d875u32 {
53
        // |x| >= 91.92277 it's infinity
54
0
        return f32::INFINITY;
55
0
    }
56
57
0
    if xb <= 0x40f80000u32 {
58
        // |x| <= 7.75
59
0
        if xb <= 0x34000000u32 {
60
            // |x| <= f32::EPSILON
61
0
            let dx = x as f64;
62
            const R: f64 = 1. / 8.;
63
0
            return (dx * dx * R) as f32;
64
0
        }
65
0
        return i2f_small(f32::from_bits(xb));
66
0
    }
67
68
0
    i2f_asympt(f32::from_bits(xb))
69
0
}
70
71
/**
72
Computes
73
I2(x) = x^2 * R(x^2)
74
75
Generated by Wolfram Mathematica:
76
77
```text
78
<<FunctionApproximations`
79
ClearAll["Global`*"]
80
f[x_]:=BesselI[2,x]/x^2
81
g[z_]:=f[Sqrt[z]]
82
{err,approx}=MiniMaxApproximation[g[z],{z,{0.000000000001,7.75},8,7},WorkingPrecision->75]
83
poly=Numerator[approx][[1]];
84
coeffs=CoefficientList[poly,z];
85
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
86
poly=Denominator[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
```
90
**/
91
#[inline]
92
0
fn i2f_small(x: f32) -> f32 {
93
0
    let dx = x as f64;
94
0
    let x_sqr = dx * dx;
95
96
0
    let p_num = f_estrin_polyeval9(
97
0
        x_sqr,
98
0
        f64::from_bits(0x3fc0000000000000),
99
0
        f64::from_bits(0x3f831469a38d72c7),
100
0
        f64::from_bits(0x3f2f453dd3dd98f4),
101
0
        f64::from_bits(0x3ec8af52ee8fce9b),
102
0
        f64::from_bits(0x3e5589f2cb4e0ec9),
103
0
        f64::from_bits(0x3dd60fa268a4206d),
104
0
        f64::from_bits(0x3d4ab3091ee18d6b),
105
0
        f64::from_bits(0x3cb1efec43b15186),
106
0
        f64::from_bits(0x3c050992c6e9e63f),
107
    );
108
0
    let p_den = f_estrin_polyeval8(
109
0
        x_sqr,
110
0
        f64::from_bits(0x3ff0000000000000),
111
0
        f64::from_bits(0xbf82075d8e3f1476),
112
0
        f64::from_bits(0x3f03ef86564a284b),
113
0
        f64::from_bits(0xbe7c498fab4a57d8),
114
0
        f64::from_bits(0x3dec162ca0f68486),
115
0
        f64::from_bits(0xbd53bb6398461540),
116
0
        f64::from_bits(0x3cb265215261e64a),
117
0
        f64::from_bits(0xbc01cf52cc350e81),
118
    );
119
0
    let p = p_num / p_den;
120
0
    (p * x_sqr) as f32
121
0
}
122
123
/**
124
Asymptotic expansion for I2.
125
126
Computes:
127
sqrt(x) * exp(-x) * I2(x) = Pn(1/x)/Qn(1/x)
128
hence:
129
I2(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x)
130
131
Generated by Mathematica:
132
```text
133
<<FunctionApproximations`
134
ClearAll["Global`*"]
135
f[x_]:=Sqrt[x] Exp[-x] BesselI[2,x]
136
g[z_]:=f[1/z]
137
{err,approx}=MiniMaxApproximation[g[z],{z,{1/92.3,1/7.5},8,8},WorkingPrecision->70]
138
poly=Numerator[approx][[1]];
139
coeffs=CoefficientList[poly,z];
140
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
141
poly=Denominator[approx][[1]];
142
coeffs=CoefficientList[poly,z];
143
TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
144
```
145
**/
146
#[inline]
147
0
fn i2f_asympt(x: f32) -> f32 {
148
0
    let dx = x as f64;
149
0
    let recip = 1. / dx;
150
0
    let p_num = f_estrin_polyeval9(
151
0
        recip,
152
0
        f64::from_bits(0x3fd9884533d45f46),
153
0
        f64::from_bits(0xc02b979526807e1e),
154
0
        f64::from_bits(0x406b1dd3e795bbed),
155
0
        f64::from_bits(0xc09e43629031ec91),
156
0
        f64::from_bits(0x40c48c03a39aec1d),
157
0
        f64::from_bits(0xc0e0f022ccb8807a),
158
0
        f64::from_bits(0x40f0302eeb22a776),
159
0
        f64::from_bits(0xc0f02b01549d38b8),
160
0
        f64::from_bits(0x40dad4e70f2bc264),
161
    );
162
0
    let p_den = f_estrin_polyeval9(
163
0
        recip,
164
0
        f64::from_bits(0x3ff0000000000000),
165
0
        f64::from_bits(0xc0405a71a88b191c),
166
0
        f64::from_bits(0x407e19f7d247d098),
167
0
        f64::from_bits(0xc0aeaac6e0ca17fe),
168
0
        f64::from_bits(0x40d2301702f40a98),
169
0
        f64::from_bits(0xc0e7e6c6c01841b3),
170
0
        f64::from_bits(0x40ed67317e9e46cc),
171
0
        f64::from_bits(0xc0d13786aa1ef416),
172
0
        f64::from_bits(0xc0a6c9cfe579ae22),
173
    );
174
0
    let z = p_num / p_den;
175
176
0
    let e = core_expf(x);
177
0
    let r_sqrt = j1f_rsqrt(dx);
178
0
    (z * r_sqrt * e) as f32
179
0
}
180
181
#[cfg(test)]
182
mod tests {
183
    use super::*;
184
    #[test]
185
    fn test_i2f() {
186
        assert_eq!(f_i2f(0.), 0.);
187
        assert_eq!(f_i2f(f32::INFINITY), f32::INFINITY);
188
        assert_eq!(f_i2f(f32::NEG_INFINITY), f32::INFINITY);
189
        assert_eq!(f_i2f(1.), 0.13574767);
190
        assert_eq!(f_i2f(-1.), 0.13574767);
191
        assert_eq!(f_i2f(9.432), 1314.6553);
192
        assert_eq!(f_i2f(-9.432), 1314.6553);
193
    }
194
}