Skip to content

Commit aeddfe7

Browse files
committed
continued fraction
1 parent a09b94d commit aeddfe7

File tree

4 files changed

+90
-35
lines changed

4 files changed

+90
-35
lines changed

src/U_polynomials.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ function Uk_poly_Hankel(p, v, p2, x::T) where T <: Float64
7070
end
7171
Uk_poly_Hankel(p, v, p2, x) = Uk_poly_Jn(p, v, p2, x::BigFloat)
7272

73-
Uk_poly_In(p, v, p2, ::Type{Float32}) = Uk_poly3(p, v, p2)[1]
74-
Uk_poly_In(p, v, p2, ::Type{Float64}) = Uk_poly5(p, v, p2)[1]
75-
Uk_poly_Kn(p, v, p2, ::Type{Float32}) = Uk_poly3(p, v, p2)[2]
76-
Uk_poly_Kn(p, v, p2, ::Type{Float64}) = Uk_poly5(p, v, p2)[2]
73+
Uk_poly_In(p, v, p2, ::Type{Float32}) = Uk_poly5(p, v, p2)[1]
74+
Uk_poly_In(p, v, p2, ::Type{Float64}) = Uk_poly10(p, v, p2)[1]
75+
Uk_poly_Kn(p, v, p2, ::Type{Float32}) = Uk_poly5(p, v, p2)[2]
76+
Uk_poly_Kn(p, v, p2, ::Type{Float64}) = Uk_poly10(p, v, p2)[2]
7777

7878
@inline function split_evalpoly(x, P)
7979
# polynomial P must have an even number of terms

src/besseli.jl

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,18 +139,15 @@ Nu must be real.
139139
function besseli(nu, x::T) where T <: Union{Float32, Float64}
140140
nu == 0 && return besseli0(x)
141141
nu == 1 && return besseli1(x)
142-
143-
if x > maximum((T(30), nu^2 / 4))
142+
143+
if x > maximum((T(30), nu^2 / 6))
144144
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))
149-
else
145+
elseif nu > 25.0 || x > 35.0
150146
return T(besseli_large_orders(nu, x))
147+
else
148+
return T(besseli_power_series(nu, x))
151149
end
152150
end
153-
154151
"""
155152
besselix(nu, x::T) where T <: Union{Float32, Float64}
156153
@@ -264,25 +261,16 @@ function besseli_large_argument_scaled(v, z::T) where T
264261
return res * coef
265262
end
266263

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))
264+
function besseli_power_series(v, x::T) where T
265+
MaxIter = 3000
266+
out = zero(T)
267+
xs = (x/2)^v
268+
a = xs / gamma(v + one(T))
269+
t2 = (x/2)^2
270+
for i in 0:MaxIter
284271
out += a
285-
a <= eps(T) && break
272+
abs(a) < eps(T) * abs(out) && break
273+
a *= inv((v + i + one(T)) * (i + one(T))) * t2
286274
end
287-
return coef * out
275+
return out
288276
end

src/besselk.jl

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ In other words, for large values of x and small to moderate values of nu,
153153
this routine will underflow to zero.
154154
For small to medium values of x and large values of nu this will overflow and return Inf.
155155
=#
156+
#=
156157
"""
157158
besselk(x::T) where T <: Union{Float32, Float64}
158159
@@ -166,7 +167,7 @@ function besselk(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
166167
return besselk_large_orders(nu, x)
167168
end
168169
end
169-
170+
=#
170171
"""
171172
besselk(x::T) where T <: Union{Float32, Float64}
172173
@@ -203,4 +204,70 @@ function besselk_large_orders_scaled(v, x::T) where T <: Union{Float32, Float64,
203204
p2 = v^2/fma(max(v,x), max(v,x), min(v,x)^2)
204205

205206
return T(coef*Uk_poly_Kn(p, v, p2, T))
206-
end
207+
end
208+
209+
function besselk(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
210+
(isinteger(nu) && nu < 250) && return besselk_up_recurrence(x, besselk1(x), besselk0(x), 1, nu)[1]
211+
212+
if nu > 25.0 || x > 35.0
213+
return besselk_large_orders(nu, x)
214+
else
215+
return besselk_continued_fraction(nu, x)
216+
end
217+
end
218+
219+
# could also use the continued fraction for inu/inmu1
220+
# but it seems like adapting the besseli_power series
221+
# to give both nu and nu-1 is faster
222+
223+
#inum1 = besseli_power_series(nu-1, x)
224+
#H_inu = steed(nu, x)
225+
#inu = besseli_power_series(nu, x)#inum1 * H_inu
226+
function besselk_continued_fraction(nu, x)
227+
inu, inum1 = besseli_power_series_inu_inum1(nu, x)
228+
H_knu = besselk_ratio_knu_knup1(nu-1, x)
229+
return 1 / (x * (inum1 + inu / H_knu))
230+
end
231+
232+
function besseli_power_series_inu_inum1(v, x::T) where T
233+
MaxIter = 3000
234+
out = zero(T)
235+
out2 = zero(T)
236+
x2 = x / 2
237+
xs = (x2)^v
238+
gmx = xs / gamma(v)
239+
a = gmx / v
240+
b = gmx / x2
241+
t2 = x2*x2
242+
for i in 0:MaxIter
243+
out += a
244+
out2 += b
245+
abs(a) < eps(T) * abs(out) && break
246+
a *= inv((v + i + one(T)) * (i + one(T))) * t2
247+
b *= inv((v + i) * (i + one(T))) * t2
248+
end
249+
return out, out2
250+
end
251+
252+
253+
# slightly modified version of https://github.com/heltonmc/Bessels.jl/issues/17#issuecomment-1195726642 from @cgeoga
254+
function besselk_ratio_knu_knup1(v, x::T) where T
255+
MaxIter = 1000
256+
# do the modified Lentz method:
257+
(hn, Dn, Cn) = (1e-50, zero(v), 1e-50)
258+
259+
jf = one(T)
260+
vv = v*v
261+
for _ in 1:MaxIter
262+
an = (vv - ((2*jf - 1)^2) * T(0.25))
263+
bn = 2 * (x + jf)
264+
Cn = an / Cn + bn
265+
Dn = inv(muladd(an, Dn, bn))
266+
del = Dn * Cn
267+
hn *= del
268+
abs(del - 1) < eps(T) && break
269+
jf += one(T)
270+
end
271+
xinv = inv(x)
272+
return xinv * (v + x + 1/2) + xinv * hn
273+
end

src/recurrence.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ end
3636
return jnup1, jnu
3737
end
3838

39-
#=
39+
4040
# currently not used
4141
# backward recurrence relation for besselk and besseli
4242
# outputs both (bessel(x, nu_end), bessel(x, nu_end-1)
@@ -50,4 +50,4 @@ end
5050
end
5151
return jnup1, jnu
5252
end
53-
=#
53+

0 commit comments

Comments
 (0)