Skip to content

Commit ef50a45

Browse files
committed
update cutoffs and add tests
1 parent 4303a0f commit ef50a45

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

src/U_polynomials.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function besseljy_debye(v, x)
2626

2727
return coef_Jn * Uk_Jn, coef_Yn * Uk_Yn
2828
end
29-
hankel_debye_cutoff(nu, x) = nu < -0.0657 + 0.9976*x + Base.Math._approx_cbrt(-276.915*x)
29+
hankel_debye_cutoff(nu, x) = nu < 0.2 + x + Base.Math._approx_cbrt(-411*x)
3030

3131
# valid when v < x (uniform asymptotic expansions)
3232
"""

src/bessely.jl

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,27 @@ function _bessely1_compute(x::Float64)
139139
p = p * sc[1] + w * q * sc[2]
140140
return p * SQ2OPI(T) / sqrt(x)
141141
else
142-
143-
return besseljy_large_argument(1.0, x)[2]
142+
xinv = inv(x)
143+
x2 = xinv*xinv
144+
if x < 130.0
145+
p1 = (one(T), 3/16, -99/512, 6597/8192, -4057965/524288, 1113686901/8388608, -951148335159/268435456, 581513783771781/4294967296)
146+
q1 = (3/8, -21/128, 1899/5120, -543483/229376, 8027901/262144, -30413055339/46137344, 9228545313147/436207616)
147+
p = evalpoly(x2, p1)
148+
q = evalpoly(x2, q1)
149+
else
150+
p2 = (one(T), 3/16, -99/512, 6597/8192)
151+
q2 = (3/8, -21/128, 1899/5120, -543483/229376)
152+
p = evalpoly(x2, p2)
153+
q = evalpoly(x2, q2)
154+
end
155+
156+
a = SQ2OPI(T) * sqrt(xinv) * p
157+
xn = muladd(xinv, q, - 3 * PIO4(T))
158+
159+
# the following computes b = sin(x + xn) more accurately
160+
# see src/misc.jl
161+
b = sin_sum(x, xn)
162+
return a * b
144163
end
145164
end
146165
function _bessely1_compute(x::Float32)
@@ -172,18 +191,18 @@ function _bessely(nu, x::T) where T
172191
nu == 0 && return bessely0(x)
173192
nu == 1 && return bessely1(x)
174193

175-
# large argument branch see src/asymptotics.jl
176-
besseljy_large_argument_cutoff(nu, x) && return besseljy_large_argument(nu, x)[2]
177-
178194
# x < ~nu branch see src/U_polynomials.jl
179195
besseljy_debye_cutoff(nu, x) && return besseljy_debye(nu, x)[2]
180196

181197
# x > ~nu branch see src/U_polynomials.jl on computing Hankel function
182198
hankel_debye_cutoff(nu, x) && return imag(hankel_debye(nu, x))
183199

184-
# use forward recurrence if nu is an integer up until it becomes inefficient
200+
# large argument branch see src/asymptotics.jl
201+
besseljy_large_argument_cutoff(nu, x) && return besseljy_large_argument(nu, x)[2]
202+
203+
# use forward recurrence if nu is an integer up until it becomes inefficient
185204
(isinteger(nu) && nu < 250) && return besselj_up_recurrence(x, bessely1(x), bessely0(x), 1, nu)[1]
186-
205+
187206
# use power series for small x and for when nu > x
188207
bessely_series_cutoff(nu, x) && return bessely_power_series(nu, x)
189208

@@ -192,7 +211,7 @@ function _bessely(nu, x::T) where T
192211

193212
# at this point x > 19.0 (for Float64) and fairly close to nu
194213
# shift nu down and use the debye expansion for Hankel function (valid x > nu) then use forward recurrence
195-
nu_shift = floor(nu) - ceil(Int, -4.0657 + 0.9976*x + Base.Math._approx_cbrt(-276.915*x))
214+
nu_shift = floor(nu) - ceil(Int, -1.5 + x + Base.Math._approx_cbrt(-411*x))
196215
v2 = nu - maximum((nu_shift, modf(nu)[1] + 1))
197216
return besselj_up_recurrence(x, imag(hankel_debye(v2, x)), imag(hankel_debye(v2 - 1, x)), v2, nu)[1]
198217
end

test/bessely_test.jl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# general array for testing input to SpecialFunctions.jl
2-
x = 0.01:0.01:100.0
2+
x = 0.01:0.01:150.0
33

44
### Tests for bessely0
55
y0_SpecialFunctions = SpecialFunctions.bessely0.(big.(x)) # array to be tested against computed in BigFloats
@@ -65,6 +65,23 @@ y1_32 = bessely1.(Float32.(x))
6565
@test bessely1(Inf32) == zero(Float32)
6666
@test bessely1(Inf64) == zero(Float64)
6767

68-
69-
# briefly test the large argument is working
70-
@test Bessels.besseljy_large_argument(10.0, 100.0)[2] SpecialFunctions.bessely(10.0, 100.0)
68+
## Tests for bessely
69+
70+
## test all numbers and orders for 0<nu<100
71+
x = [0.05, 0.1, 0.2, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9, 0.92, 0.95, 0.97, 0.99, 1.0, 1.01, 1.05, 1.1, 1.2, 1.4, 2.0]
72+
nu = [2, 4, 6, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100]
73+
for v in nu, xx in x
74+
xx *= v
75+
sf = SpecialFunctions.bessely(BigFloat(v), BigFloat(xx))
76+
@test isapprox(Bessels._bessely(v, xx), Float64(sf), rtol=7e-14)
77+
end
78+
79+
# test decimal orders
80+
# SpecialFunctions.jl can give errors over 1e-12 so need to soften tolerance to match
81+
# need to switch tests over to ArbNumerics.jl for better precision tests
82+
x = [0.05, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5,0.55, 0.6,0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.92, 0.95, 0.97, 0.99, 1.0, 1.01, 1.05, 1.08, 1.1, 1.2, 1.4, 1.5, 1.6, 1.8, 2.0, 2.5, 3.0, 4.0, 4.5, 4.99, 5.1]
83+
nu = [0.1, 0.4567, 0.8123, 1.5, 2.5, 4.1234, 6.8, 12.3, 18.9, 28.2345, 38.1235, 51.23, 72.23435, 80.5, 98.5, 104.2]
84+
for v in nu, xx in x
85+
xx *= v
86+
@test isapprox(Bessels._bessely(v, xx), SpecialFunctions.bessely(v, xx), rtol=5e-12)
87+
end

0 commit comments

Comments
 (0)