Skip to content

Commit a09b94d

Browse files
authored
Merge pull request #26 from heltonmc/bessely
bessely(nu, x) for positive and negative arguments
2 parents 9c62620 + 08b5626 commit a09b94d

File tree

14 files changed

+571
-144
lines changed

14 files changed

+571
-144
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
fail-fast: false
2121
matrix:
2222
version:
23-
- '1.5'
23+
- '1'
2424
- '1.6'
2525
- 'nightly'
2626
os:

src/Bessels.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ using SpecialFunctions: loggamma
44

55
export besselj0
66
export besselj1
7+
export besselj
78

89
export bessely0
910
export bessely1
11+
export bessely
1012

1113
export besseli
1214
export besselix
@@ -40,6 +42,8 @@ include("recurrence.jl")
4042
include("misc.jl")
4143
include("Polynomials/besselj_polys.jl")
4244
include("asymptotics.jl")
45+
include("gamma.jl")
46+
4347
#include("hankel.jl")
4448

4549
end

src/U_polynomials.jl

Lines changed: 57 additions & 2 deletions
Large diffs are not rendered by default.

src/asymptotics.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
#besseljy_large_argument_min(::Type{Float32}) = 15.0f0
2+
besseljy_large_argument_min(::Type{Float64}) = 20.0
3+
besseljy_large_argument_min(::Type{T}) where T <: AbstractFloat = 40.0
4+
5+
#besseljy_large_argument_cutoff(v, x::Float32) = (x > 1.2f0*v && x > besseljy_large_argument_min(Float32))
6+
besseljy_large_argument_cutoff(v, x::Float64) = (x > 1.65*v && x > besseljy_large_argument_min(Float64))
7+
besseljy_large_argument_cutoff(v, x::T) where T = (x > 4*v && x > besseljy_large_argument_min(T))
8+
9+
110
function besseljy_large_argument(v, x::T) where T
211
# gives both (besselj, bessely) for x > 1.6*v
312
α, αp = _α_αp_asymptotic(v, x)
@@ -30,6 +39,7 @@ function _α_αp_asymptotic(v, x::Float64)
3039
return _α_αp_poly_30(v, x)
3140
end
3241
end
42+
#=
3343
function _α_αp_asymptotic(v, x::Float32)
3444
if x > 4*v
3545
return _α_αp_poly_5(v, x)
@@ -39,7 +49,7 @@ function _α_αp_asymptotic(v, x::Float32)
3949
return _α_αp_poly_30(v, x)
4050
end
4151
end
42-
52+
=#
4353
# Float64
4454
# can only use for x > 20.0
4555
# 30 terms gives ~5e-16 relative error when x > 1.6*nu
@@ -74,6 +84,7 @@ end
7484
# a = 27.7479; b = 22.3588; c = 3.74567
7585
# this method requires significantly more terms when x gets closer to nu
7686
# so it becomes more efficient to use recurrence (or another algorithm) in this region
87+
#=
7788
function _α_αp_poly_5(v, x::T) where T
7889
xinv = inv(x)^2
7990
μ = 4 * T(v)^2
@@ -89,6 +100,7 @@ function _α_αp_poly_5(v, x::T) where T
89100
return α, αp
90101
return α, αp
91102
end
103+
=#
92104
function _α_αp_poly_10(v, x::T) where T
93105
xinv = inv(x)^2
94106
μ = 4 * v^2
@@ -109,6 +121,7 @@ function _α_αp_poly_10(v, x::T) where T
109121
return α, αp
110122
return α, αp
111123
end
124+
#=
112125
function _α_αp_poly_15(v, x::T) where T
113126
xinv = inv(x)^2
114127
μ = 4 * v^2
@@ -133,6 +146,7 @@ function _α_αp_poly_15(v, x::T) where T
133146
α = x * (evalpoly(xinv, (s0, -s1, -s2/3, -s3/5, -s4/7, -s5/9, -s6/11, -s7/13, -s8/15, -s9/17, -s10/19, -s11/21, -s12/23, -s13/25, -s14/27, -s15/29)))
134147
return α, αp
135148
end
149+
=#
136150
function _α_αp_poly_20(v, x::T) where T
137151
xinv = inv(x)^2
138152
μ = 4 * v^2

src/besseli.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,15 @@ end
198198
function _besseli_continued_fractions(nu, x::T) where T
199199
S = promote_type(T, Float64)
200200
xx = S(x)
201-
knu, knum1 = up_recurrence(xx, besselk0(xx), besselk1(xx), nu)
201+
knum1, knu = besselk_up_recurrence(xx, besselk1(xx), besselk0(xx), 1, nu-1)
202202
# if knu or knum1 is zero then besseli will likely overflow
203203
(iszero(knu) || iszero(knum1)) && return throw(DomainError(x, "Overflow error"))
204204
return 1 / (x * (knum1 + knu / steed(nu, x)))
205205
end
206206
function _besseli_continued_fractions_scaled(nu, x::T) where T
207207
S = promote_type(T, Float64)
208208
xx = S(x)
209-
knu, knum1 = up_recurrence(xx, besselk0x(xx), besselk1x(xx), nu)
209+
knum1, knu = besselk_up_recurrence(xx, besselk1x(xx), besselk0x(xx), 1, nu-1)
210210
# if knu or knum1 is zero then besseli will likely overflow
211211
(iszero(knu) || iszero(knum1)) && return throw(DomainError(x, "Overflow error"))
212212
return 1 / (x * (knum1 + knu / steed(nu, x)))

src/besselj.jl

Lines changed: 39 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,43 @@ function besselj1(x::Float32)
150150
return p * s
151151
end
152152
end
153-
"""
154-
besselj(nu, x::T) where T <: Union{Float32, Float64}
155153

156-
Bessel function of the first kind of order nu, ``J_{nu}(x)``.
157-
Nu must be real.
158-
"""
159-
function _besselj(nu, x)
154+
function besselj(nu::Real, x::T) where T
155+
isinteger(nu) && return besselj(Int(nu), x)
156+
abs_nu = abs(nu)
157+
abs_x = abs(x)
158+
159+
Jnu = besselj_positive_args(abs_nu, abs_x)
160+
if nu >= zero(T)
161+
return x >= zero(T) ? Jnu : Jnu * cispi(abs_nu)
162+
else
163+
Ynu = bessely_positive_args(abs_nu, abs_x)
164+
spi, cpi = sincospi(abs_nu)
165+
out = Jnu * cpi - Ynu * spi
166+
return x >= zero(T) ? out : out * cispi(nu)
167+
end
168+
end
169+
170+
function besselj(nu::Integer, x::T) where T
171+
abs_nu = abs(nu)
172+
abs_x = abs(x)
173+
sg = iseven(abs_nu) ? 1 : -1
174+
175+
Jnu = besselj_positive_args(abs_nu, abs_x)
176+
if nu >= zero(T)
177+
return x >= zero(T) ? Jnu : Jnu * sg
178+
else
179+
if x >= zero(T)
180+
return Jnu * sg
181+
else
182+
Ynu = bessely_positive_args(abs_nu, abs_x)
183+
spi, cpi = sincospi(abs_nu)
184+
return (cpi*Jnu - spi*Ynu) * sg
185+
end
186+
end
187+
end
188+
189+
function besselj_positive_args(nu::Real, x::T) where T
160190
nu == 0 && return besselj0(x)
161191
nu == 1 && return besselj1(x)
162192

@@ -172,10 +202,9 @@ function _besselj(nu, x)
172202
if nu >= x
173203
nu_shift = ceil(Int, debye_cutoff - nu)
174204
v = nu + nu_shift
175-
arr = range(v, stop = nu, length = nu_shift + 1)
176205
jnu = besseljy_debye(v, x)[1]
177206
jnup1 = besseljy_debye(v+1, x)[1]
178-
return besselj_down_recurrence(x, jnu, jnup1, arr)[2]
207+
return besselj_down_recurrence(x, jnu, jnup1, v, nu)[1]
179208
end
180209

181210
# at this point x > nu and x < nu * 1.65
@@ -192,14 +221,13 @@ function _besselj(nu, x)
192221
v2 = nu - nu_shift
193222
jnu = besseljy_large_argument(v2, x)[1]
194223
jnum1 = besseljy_large_argument(v2 - 1, x)[1]
195-
return besselj_up_recurrence(x, jnu, jnum1, v2, nu)[2]
224+
return besselj_up_recurrence(x, jnu, jnum1, v2, nu)[1]
196225
else
197226
nu_shift = ceil(Int, debye_diff)
198227
v = nu + nu_shift
199-
arr = range(v, stop = nu, length = nu_shift + 1)
200228
jnu = besseljy_debye(v, x)[1]
201229
jnup1 = besseljy_debye(v+1, x)[1]
202-
return besselj_down_recurrence(x, jnu, jnup1, arr)[2]
230+
return besselj_down_recurrence(x, jnu, jnup1, v, nu)[1]
203231
end
204232
end
205233

@@ -238,67 +266,3 @@ function log_besselj_small_arguments_orders(v, x::T) where T
238266
logout = -loggamma(v + 1) + fma(v, log(x/2), log(out))
239267
return exp(logout)
240268
end
241-
242-
# For 0.0 <= x < 171.5
243-
# Mean ULP = 0.55
244-
# Max ULP = 2.4
245-
# Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
246-
function gamma(x)
247-
if x > 11.5
248-
return large_gamma(x)
249-
elseif x < 0.0
250-
#p = floor(x)
251-
#isequal(p, abs(x)) && return throw(DomainError(x, "NaN result for non-NaN input."))
252-
# need reflection formula
253-
return throw(DomainError(x, "Negative numbers are currently not implemented"))
254-
elseif x <= 11.5
255-
return small_gamma(x)
256-
elseif isnan(x)
257-
return x
258-
end
259-
end
260-
function large_gamma(x)
261-
isinf(x) && return x
262-
T = Float64
263-
w = inv(x)
264-
s = (
265-
8.333333333333331800504e-2, 3.472222222230075327854e-3, -2.681327161876304418288e-3, -2.294719747873185405699e-4,
266-
7.840334842744753003862e-4, 6.989332260623193171870e-5, -5.950237554056330156018e-4, -2.363848809501759061727e-5,
267-
7.147391378143610789273e-4
268-
)
269-
w = w * evalpoly(w, s) + one(T)
270-
# lose precision on following block
271-
y = exp((x))
272-
# avoid overflow
273-
v = x^(0.5 * x - 0.25)
274-
y = v * (v / y)
275-
276-
return SQ2PI(T) * y * w
277-
end
278-
function small_gamma(x)
279-
T = Float64
280-
P = (
281-
1.000000000000000000009e0, 8.378004301573126728826e-1, 3.629515436640239168939e-1, 1.113062816019361559013e-1,
282-
2.385363243461108252554e-2, 4.092666828394035500949e-3, 4.542931960608009155600e-4, 4.212760487471622013093e-5
283-
)
284-
Q = (
285-
9.999999999999999999908e-1, 4.150160950588455434583e-1, -2.243510905670329164562e-1, -4.633887671244534213831e-2,
286-
2.773706565840072979165e-2, -7.955933682494738320586e-4, -1.237799246653152231188e-3, 2.346584059160635244282e-4,
287-
-1.397148517476170440917e-5
288-
)
289-
290-
z = one(T)
291-
while x >= 3.0
292-
x -= one(T)
293-
z *= x
294-
end
295-
while x < 2.0
296-
z /= x
297-
x += one(T)
298-
end
299-
300-
x -= T(2)
301-
p = evalpoly(x, P)
302-
q = evalpoly(x, Q)
303-
return z * p / q
304-
end

src/besselk.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ Modified Bessel function of the second kind of order nu, ``K_{nu}(x)``.
161161
function besselk(nu, x::T) where T <: Union{Float32, Float64, BigFloat}
162162
T == Float32 ? branch = 20 : branch = 50
163163
if nu < branch
164-
return up_recurrence(x, besselk0(x), besselk1(x), nu)[1]
164+
return besselk_up_recurrence(x, besselk1(x), besselk0(x), 1, nu)[1]
165165
else
166166
return besselk_large_orders(nu, x)
167167
end
@@ -175,7 +175,7 @@ Scaled modified Bessel function of the second kind of order nu, ``K_{nu}(x)*e^{x
175175
function besselkx(nu::Int, x::T) where T <: Union{Float32, Float64}
176176
T == Float32 ? branch = 20 : branch = 50
177177
if nu < branch
178-
return up_recurrence(x, besselk0x(x), besselk1x(x), nu)[1]
178+
return besselk_up_recurrence(x, besselk1x(x), besselk0x(x), 1, nu)[1]
179179
else
180180
return besselk_large_orders_scaled(nu, x)
181181
end

0 commit comments

Comments
 (0)