Skip to content

Commit 2c26ca7

Browse files
committed
Implement asymptotic formulas valid for large nu and small n
1 parent 890a138 commit 2c26ca7

File tree

1 file changed

+91
-1
lines changed

1 file changed

+91
-1
lines changed

src/FunctionZeros.jl

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ Asymptotic formula for the `n`th zero of the the Bessel J (Y) function of order
5454
"""
5555
function bessel_zero_asymptotic(nu_in::Real, n::Integer, kind=1)
5656
nu = abs(nu_in)
57+
if nu > 25 && n length(airy_zeros().ai)
58+
return bessel_zero_largenu_asymptotic(nu, n, kind, false)
59+
end
5760
if kind == 1
5861
beta = MathConstants.pi * (n + nu / 2 - 1//4)
5962
else # kind == 2
@@ -191,8 +194,12 @@ Asymptotic formula for the `n`th zero of the the derivative of Bessel J (Y) func
191194
of order `nu`. `kind == 1 (2)` for Bessel function of the first (second) kind, J (Y).
192195
"""
193196
function bessel_deriv_zero_asymptotic(nu_in::Real, n::Integer, kind=1)
194-
# Reference: https://dlmf.nist.gov/10.21.E20
195197
nu = abs(nu_in)
198+
if nu > 25 && n length(airy_zeros().ai)
199+
return bessel_zero_largenu_asymptotic(nu, n, kind, true)
200+
end
201+
202+
# Reference: https://dlmf.nist.gov/10.21.E20
196203
if kind == 1
197204
beta = MathConstants.pi * (n + nu / 2 - 3//4)
198205
else # kind == 2
@@ -297,4 +304,87 @@ function bessely_deriv_zero(nu::Union{Integer,Float64}, n::Integer)
297304
end
298305
end
299306

307+
"""
308+
airy_zeros()
309+
310+
Return the first few negative zeros of the functions `airyai`, `airybi`, `airyaiprime`, and `airybiprime`
311+
312+
## Return Value
313+
- `(; ai, bi, aiprime, biprime)`: A named tuple containing the first few negative zeros of the functions
314+
`airyai`, `airybi`, `airyaiprime`, and `airybiprime`, respectively, as defined in the `SpecialFunctions`
315+
package. Each field in the named tuple consists of a tuple of `n` increasingly negative values. Here `n`
316+
is a small integer, say 2 or 3.
317+
"""
318+
@inline function airy_zeros()
319+
ai = (-2.338107410459767, -4.087949444130973, -5.520559828095556)
320+
bi = (-1.173713222709127, -3.2710933028363516, -4.8307378416620095)
321+
aiprime = (-1.0187929716474717, -3.248197582179841, -4.820099211178737)
322+
biprime = (-2.2944396826141227, -4.073155089071816, -5.5123957296635835)
323+
return (; ai, bi, aiprime, biprime)
324+
end
325+
326+
"""
327+
bessel_zero_largenu_asymptotic(nu::Real, m::Integer, kind::Integer, deriv::Bool)
328+
329+
Compute an asymptotic approximation for a zero of the J or Y Bessel function (or their derivative) suitable for large order.
330+
331+
## Input Arguments
332+
- `nu`: The (nonnegative) order of the Bessel function.
333+
- `m`: A small positive integer enumerating which zero is sought. Can not exceed `length(airy_zeros().ai)`.
334+
The asymptotic formulas used herein weaken as `m` increases.
335+
- `kind`: Kind of Bessel function whose zero is sought. Either 1 for the J Bessel function or 2 for the Y Bessel function.
336+
- `deriv`: If false, returns the zero of the function. If true, returns the zero of the function's derivative.
337+
338+
## Return Value
339+
`z`: A `Float64` approximation of the desired zero.
340+
341+
## Reference
342+
- https://dlmf.nist.gov/10.21.vii
343+
"""
344+
function bessel_zero_largenu_asymptotic(nu::Real, m::Integer, kind::Integer, deriv::Bool)
345+
abfactor = inv(cbrt(2.0))
346+
347+
if kind == 1
348+
alpha = -abfactor * (deriv ? airy_zeros().aiprime[m] : airy_zeros().ai[m])
349+
elseif kind == 2
350+
alpha = -abfactor * (deriv ? airy_zeros().biprime[m] : airy_zeros().bi[m])
351+
else
352+
throw(ArgumentError("kind must be 1 or 2 but is $kind"))
353+
end
354+
355+
alphap2 = alpha * alpha
356+
alphap3 = alpha * alphap2
357+
alphap4 = alpha * alphap3
358+
alphap5 = alpha * alphap4
359+
360+
alpha0 = 1.0
361+
alpha1 = alpha
362+
363+
if deriv
364+
alpha2 = 3 * alphap2 / 10 - inv(10 * alpha)
365+
alpha3 = -(alphap3 / 350 + inv(25) + inv(200 * alphap3))
366+
alpha4 = -479 * alphap4 / 630_000 + 509 * alpha / 31_500 + inv(1500 * alphap2) - inv(2_000 * alphap5)
367+
alpha5 = 0.0
368+
else
369+
alpha2 = 3 * alphap2 / 10
370+
alpha3 = -alphap3 / 350 + inv(70)
371+
alpha4 = -(479 * alphap4 / 63_000 + alpha / 3150)
372+
alpha5 = 20_231 * alphap5 / 8_085_000 - 551 * alphap2 / 161_700
373+
end
374+
375+
x = inv(cbrt(nu)^2)
376+
xpk = 1.0
377+
zsum = lastterm = alpha0
378+
for alphak in (alpha1, alpha2, alpha3, alpha4, alpha5)
379+
xpk *= x
380+
nextterm = alphak * xpk
381+
abs(nextterm) > abs(lastterm) && break # Asymptotic series starting to diverge
382+
zsum += nextterm
383+
lastterm = nextterm
384+
end
385+
386+
zsum *= nu
387+
return zsum
388+
end
389+
300390
end # module FunctionZeros

0 commit comments

Comments
 (0)