Skip to content

Commit 4f2219d

Browse files
committed
use cont fractions
1 parent e0f094b commit 4f2219d

File tree

2 files changed

+48
-19
lines changed

2 files changed

+48
-19
lines changed

src/besseli.jl

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,16 @@ end
136136
Modified Bessel function of the first kind of order nu, ``I_{nu}(x)``.
137137
Nu must be real.
138138
"""
139-
function besseli(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
139+
function besseli(nu, x::T) where T <: Union{Float32, Float64}
140140
nu == 0 && return besseli0(x)
141141
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(50), nu^2 / 2))
144+
return T(besseli_large_argument(nu, x))
145+
elseif nu < 100
146+
return T(_besseli_continued_fractions(nu, x))
148147
else
149-
return besseli_large_orders(nu, x)
148+
return T(besseli_large_orders(nu, x))
150149
end
151150
end
152151

@@ -156,7 +155,7 @@ end
156155
Scaled modified Bessel function of the first kind of order nu, ``I_{nu}(x)*e^{-x}``.
157156
Nu must be real.
158157
"""
159-
function besselix(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
158+
function besselix(nu, x::T) where T <: Union{Float32, Float64}
160159
nu == 0 && return besseli0x(x)
161160
nu == 1 && return besseli1x(x)
162161

@@ -169,7 +168,7 @@ function besselix(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
169168
return besseli_large_orders_scaled(nu, x)
170169
end
171170
end
172-
function besseli_large_orders(v, x::T) where T <: Union{Float32, Float64, BigFloat}
171+
function besseli_large_orders(v, x::T) where T <: Union{Float32, Float64}
173172
S = promote_type(T, Float64)
174173
x = S(x)
175174
z = x / v
@@ -179,9 +178,9 @@ function besseli_large_orders(v, x::T) where T <: Union{Float32, Float64, BigFlo
179178
p = inv(zs)
180179
p2 = v^2/fma(max(v,x), max(v,x), min(v,x)^2)
181180

182-
return T(coef*Uk_poly_In(p, v, p2, T))
181+
return T(coef*Uk_poly_In(p, v, p2, Float64))
183182
end
184-
function besseli_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64, BigFloat}
183+
function besseli_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64}
185184
S = promote_type(T, Float64)
186185
x = S(x)
187186
z = x / v
@@ -194,19 +193,22 @@ function besseli_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64,
194193
return T(coef*Uk_poly_In(p, v, p2, T))
195194
end
196195

197-
function _besseli_continued_fractions(nu, x)
198-
knu, knum1 = up_recurrence(x, besselk0(x), besselk1(x), nu)
196+
function _besseli_continued_fractions(nu, x::T) where T
197+
S = promote_type(T, Float64)
198+
xx = S(x)
199+
knu, knum1 = up_recurrence(xx, besselk0(xx), besselk1(xx), nu)
199200
return 1 / (x * (knum1 + knu / steed(nu, x)))
200201
end
201202

202203
function steed(n, x::T) where T
204+
MaxIter = 1000
203205
xinv = inv(x)
204206
xinv2 = 2 * xinv
205207
d = x / (n + n)
206208
a = d
207209
h = a
208210
b = muladd(2, n, 2) * xinv
209-
for _ in 1:100000
211+
for _ in 1:MaxIter
210212
d = inv(b + d)
211213
a = muladd(b, d, -1) * a
212214
h = h + a
@@ -215,3 +217,23 @@ function steed(n, x::T) where T
215217
end
216218
return h
217219
end
220+
221+
function besseli_large_argument(v, z::T) where T
222+
MaxIter = 1000
223+
S = promote_type(T, Float64)
224+
z = S(z)
225+
coef = exp(z) / sqrt(2*S(pi)*z)
226+
fv2 = 4v^2
227+
term = one(S)
228+
res = term
229+
s = -term
230+
for i in 1:MaxIter
231+
offset = muladd(2, i, -1)
232+
term *= S(0.125)*(muladd(offset, -offset, fv2)) / (z*i)
233+
res = muladd(term, s, res)
234+
s = -s
235+
abs(term) <= eps(T) && break
236+
end
237+
return res*coef
238+
end
239+

test/besseli_test.jl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,20 @@ i1x_32 = besseli1x.(Float32.(x32))
6868

6969
# test for besseli
7070
# test small arguments and order
71-
m = 0:1:200; x = 0.1f0:0.5f0:90.0f0
72-
t = [besseli(m, x) for m in m, x in x]
73-
@test t[10] isa Float32
74-
@test t Float32.([SpecialFunctions.besseli(m, x) for m in m, x in x])
71+
m = 0:1:200; x = 0.5f0:0.5f0:90.0f0
72+
@test besseli(10, 1.0f0) isa Float32
73+
@test besseli(2, 80.0f0) isa Float32
74+
@test besseli(112, 80.0f0) isa Float32
75+
76+
for m in m, x in x
77+
@test besseli(m, x) Float32(SpecialFunctions.besseli(m, x))
78+
end
7579

7680
#Float 64
7781
m = 0:1:200; x = 0.1:0.5:150.0
82+
@test besseli(10, 1.0) isa Float64
83+
@test besseli(2, 80.0) isa Float64
84+
@test besseli(112, 80.0) isa Float64
7885
t = [besseli(m, x) for m in m, x in x]
7986

8087
@test t[10] isa Float64

0 commit comments

Comments
 (0)