@@ -136,17 +136,18 @@ end
136
136
Modified Bessel function of the first kind of order nu, ``I_{nu}(x)``.
137
137
Nu must be real.
138
138
"""
139
- function besseli (nu, x:: T ) where T <: Union{Float32, Float64, BigFloat }
139
+ function besseli (nu, x:: T ) where T <: Union{Float32, Float64}
140
140
nu == 0 && return besseli0 (x)
141
141
nu == 1 && return besseli1 (x)
142
-
143
- branch = 60
144
- if nu < branch
145
- inp1 = besseli_large_orders (branch + 1 , x)
146
- in = besseli_large_orders (branch, x)
147
- return down_recurrence (x, in, inp1, nu, branch)
142
+
143
+ if x > maximum ((T (30 ), nu^ 2 / 4 ))
144
+ return T (besseli_large_argument (nu, x))
145
+ elseif x <= 2 * sqrt (nu + 1 )
146
+ return T (besseli_small_arguments (nu, x))
147
+ elseif nu < 100
148
+ return T (_besseli_continued_fractions (nu, x))
148
149
else
149
- return besseli_large_orders (nu, x)
150
+ return T ( besseli_large_orders (nu, x) )
150
151
end
151
152
end
152
153
@@ -156,20 +157,21 @@ end
156
157
Scaled modified Bessel function of the first kind of order nu, ``I_{nu}(x)*e^{-x}``.
157
158
Nu must be real.
158
159
"""
159
- function besselix (nu, x:: T ) where T <: Union{Float32, Float64, BigFloat }
160
+ function besselix (nu, x:: T ) where T <: Union{Float32, Float64}
160
161
nu == 0 && return besseli0x (x)
161
162
nu == 1 && return besseli1x (x)
162
163
163
- branch = 60
164
- if nu < branch
165
- inp1 = besseli_large_orders_scaled (branch + 1 , x)
166
- in = besseli_large_orders_scaled (branch, x)
167
- return down_recurrence (x, in, inp1, nu, branch)
164
+ if x > maximum ((T (30 ), nu^ 2 / 4 ))
165
+ return T (besseli_large_argument_scaled (nu, x))
166
+ elseif x <= 2 * sqrt (nu + 1 )
167
+ return T (besseli_small_arguments (nu, x)) * exp (- x)
168
+ elseif nu < 100
169
+ return T (_besseli_continued_fractions_scaled (nu, x))
168
170
else
169
171
return besseli_large_orders_scaled (nu, x)
170
172
end
171
173
end
172
- function besseli_large_orders (v, x:: T ) where T <: Union{Float32, Float64, BigFloat }
174
+ function besseli_large_orders (v, x:: T ) where T <: Union{Float32, Float64}
173
175
S = promote_type (T, Float64)
174
176
x = S (x)
175
177
z = x / v
@@ -179,9 +181,9 @@ function besseli_large_orders(v, x::T) where T <: Union{Float32, Float64, BigFlo
179
181
p = inv (zs)
180
182
p2 = v^ 2 / fma (max (v,x), max (v,x), min (v,x)^ 2 )
181
183
182
- return T ( coef* Uk_poly_In (p, v, p2, T) )
184
+ return coef* Uk_poly_In (p, v, p2, T)
183
185
end
184
- function besseli_large_orders_scaled (v, x:: T ) where T <: Union{Float32, Float64, BigFloat }
186
+ function besseli_large_orders_scaled (v, x:: T ) where T <: Union{Float32, Float64}
185
187
S = promote_type (T, Float64)
186
188
x = S (x)
187
189
z = x / v
@@ -193,3 +195,94 @@ function besseli_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64,
193
195
194
196
return T (coef* Uk_poly_In (p, v, p2, T))
195
197
end
198
+ function _besseli_continued_fractions (nu, x:: T ) where T
199
+ S = promote_type (T, Float64)
200
+ xx = S (x)
201
+ knu, knum1 = up_recurrence (xx, besselk0 (xx), besselk1 (xx), nu)
202
+ # if knu or knum1 is zero then besseli will likely overflow
203
+ (iszero (knu) || iszero (knum1)) && return throw (DomainError (x, " Overflow error" ))
204
+ return 1 / (x * (knum1 + knu / steed (nu, x)))
205
+ end
206
+ function _besseli_continued_fractions_scaled (nu, x:: T ) where T
207
+ S = promote_type (T, Float64)
208
+ xx = S (x)
209
+ knu, knum1 = up_recurrence (xx, besselk0x (xx), besselk1x (xx), nu)
210
+ # if knu or knum1 is zero then besseli will likely overflow
211
+ (iszero (knu) || iszero (knum1)) && return throw (DomainError (x, " Overflow error" ))
212
+ return 1 / (x * (knum1 + knu / steed (nu, x)))
213
+ end
214
+ function steed (n, x:: T ) where T
215
+ MaxIter = 1000
216
+ xinv = inv (x)
217
+ xinv2 = 2 * xinv
218
+ d = x / (n + n)
219
+ a = d
220
+ h = a
221
+ b = muladd (2 , n, 2 ) * xinv
222
+ for _ in 1 : MaxIter
223
+ d = inv (b + d)
224
+ a *= muladd (b, d, - 1 )
225
+ h = h + a
226
+ b = b + xinv2
227
+ abs (a / h) <= eps (T) && break
228
+ end
229
+ return h
230
+ end
231
+ function besseli_large_argument (v, z:: T ) where T
232
+ MaxIter = 1000
233
+ a = exp (z / 2 )
234
+ coef = a / sqrt (2 * T (pi ) * z)
235
+ fv2 = 4 * v^ 2
236
+ term = one (T)
237
+ res = term
238
+ s = - term
239
+ for i in 1 : MaxIter
240
+ i = T (i)
241
+ offset = muladd (2 , i, - 1 )
242
+ term *= T (0.125 ) * muladd (offset, - offset, fv2) / (z * i)
243
+ res = muladd (term, s, res)
244
+ s = - s
245
+ abs (term) <= eps (T) && break
246
+ end
247
+ return res * coef * a
248
+ end
249
+ function besseli_large_argument_scaled (v, z:: T ) where T
250
+ MaxIter = 1000
251
+ coef = inv (sqrt (2 * T (pi ) * z))
252
+ fv2 = 4 * v^ 2
253
+ term = one (T)
254
+ res = term
255
+ s = - term
256
+ for i in 1 : MaxIter
257
+ i = T (i)
258
+ offset = muladd (2 , i, - 1 )
259
+ term *= T (0.125 ) * muladd (offset, - offset, fv2) / (z * i)
260
+ res = muladd (term, s, res)
261
+ s = - s
262
+ abs (term) <= eps (T) && break
263
+ end
264
+ return res * coef
265
+ end
266
+
267
+ function besseli_small_arguments (v, z:: T ) where T
268
+ S = promote_type (T, Float64)
269
+ x = S (z)
270
+ if v < 20
271
+ coef = (x / 2 )^ v / factorial (v)
272
+ else
273
+ vinv = inv (v)
274
+ coef = sqrt (vinv / (2 * π)) * MathConstants. e^ (v * (log (x / (2 * v)) + 1 ))
275
+ coef *= evalpoly (vinv, (1 , - 1 / 12 , 1 / 288 , 139 / 51840 , - 571 / 2488320 , - 163879 / 209018880 , 5246819 / 75246796800 , 534703531 / 902961561600 ))
276
+ end
277
+
278
+ MaxIter = 1000
279
+ out = one (S)
280
+ zz = x^ 2 / 4
281
+ a = one (S)
282
+ for k in 1 : MaxIter
283
+ a *= zz / (k * (k + v))
284
+ out += a
285
+ a <= eps (T) && break
286
+ end
287
+ return coef * out
288
+ end
0 commit comments