Skip to content

Commit 5393cc8

Browse files
committed
update continued fractions
1 parent b9d0ef1 commit 5393cc8

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

src/besseli.jl

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,12 @@ function besselix(nu, x::T) where T <: Union{Float32, Float64}
161161
nu == 0 && return besseli0x(x)
162162
nu == 1 && return besseli1x(x)
163163

164-
branch = 60
165-
if nu < branch
166-
inup1 = besseli_large_orders_scaled(branch + 1, x)
167-
inu = besseli_large_orders_scaled(branch, x)
168-
return down_recurrence(x, inu, inup1, 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))
169170
else
170171
return besseli_large_orders_scaled(nu, x)
171172
end
@@ -194,7 +195,6 @@ function besseli_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64}
194195

195196
return T(coef*Uk_poly_In(p, v, p2, T))
196197
end
197-
198198
function _besseli_continued_fractions(nu, x::T) where T
199199
S = promote_type(T, Float64)
200200
xx = S(x)
@@ -203,6 +203,14 @@ function _besseli_continued_fractions(nu, x::T) where T
203203
(iszero(knu) || iszero(knum1)) && return throw(DomainError(x, "Overflow error"))
204204
return 1 / (x * (knum1 + knu / steed(nu, x)))
205205
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
206214
function steed(n, x::T) where T
207215
MaxIter = 1000
208216
xinv = inv(x)
@@ -220,7 +228,6 @@ function steed(n, x::T) where T
220228
end
221229
return h
222230
end
223-
224231
function besseli_large_argument(v, z::T) where T
225232
MaxIter = 1000
226233
a = exp(z / 2)
@@ -239,6 +246,23 @@ function besseli_large_argument(v, z::T) where T
239246
end
240247
return res * coef * a
241248
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
242266

243267
function besseli_small_arguments(v, z::T) where T
244268
S = promote_type(T, Float64)

src/recurrence.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# no longer used for besseli but could be used in future for Jn, Yn
2+
#=
13
@inline function down_recurrence(x, in, inp1, nu, branch)
24
# this prevents us from looping through large values of nu when the loop will always return zero
35
(iszero(in) || iszero(inp1)) && return zero(x)
@@ -13,6 +15,7 @@
1315
end
1416
return inm1
1517
end
18+
=#
1619
@inline function up_recurrence(x, k0, k1, nu)
1720
nu == 0 && return k0
1821
nu == 1 && return k1

test/besseli_test.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ t = [besseli(m, x) for m in m, x in x]
8787
@test t[10] isa Float64
8888
@test t [SpecialFunctions.besseli(m, x) for m in m, x in x]
8989

90-
@test besselix(10, 2.0) SpecialFunctions.besselix(10, 2.0)
91-
@test besselix(100, 14.0) SpecialFunctions.besselix(100, 14.0)
92-
@test besselix(120, 504.0) SpecialFunctions.besselix(120, 504.0)
90+
t = [besselix(m, x) for m in m, x in x]
91+
@test t[10] isa Float64
92+
@test t [SpecialFunctions.besselix(m, x) for m in m, x in x]
93+

0 commit comments

Comments
 (0)