Skip to content

Commit b167f1a

Browse files
committed
check for underflow
1 parent ea701f7 commit b167f1a

File tree

3 files changed

+19
-2
lines changed

3 files changed

+19
-2
lines changed

src/bessely.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ end
336336
# this works well for small arguments x < 7.0 for rel. error ~1e-14
337337
# this also works well for nu > 1.35x - 4.5
338338
# for nu > 25 more cancellation occurs near integer values
339+
# There could be premature underflow when (x/2)^v == 0.
340+
# It might be better to use logarithms (when we get loggamma julia implementation)
339341
"""
340342
bessely_power_series(nu, x::T) where T <: Float64
341343
@@ -348,6 +350,9 @@ function bessely_power_series(v, x::T) where T
348350
out = zero(T)
349351
out2 = zero(T)
350352
a = (x/2)^v
353+
# check for underflow and return limit for small arguments
354+
iszero(a) && return -T(Inf)
355+
351356
b = inv(a)
352357
a /= gamma(v + one(T))
353358
b /= gamma(-v + one(T))

src/recurrence.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ end
1515
# outputs both (bessel(x, nu_end), bessel(x, nu_end+1)
1616
# x = 0.1; y0 = bessely0(x); y1 = bessely1(x);
1717
# besselj_up_recurrence(x, y1, y0, 1, 5) will give bessely(5, x)
18-
@inline function besselj_up_recurrence(x, jnu, jnum1, nu_start, nu_end)
18+
@inline function besselj_up_recurrence(x::T, jnu, jnum1, nu_start, nu_end) where T
1919
x2 = 2 / x
2020
while nu_start < nu_end + 0.5 # avoid inexact floating points when nu isa float
2121
jnum1, jnu = jnu, muladd(nu_start*x2, jnu, -jnum1)
2222
nu_start += 1
2323
end
24-
return jnum1, jnu
24+
# need to check if NaN resulted during loop from subtraction of infinities
25+
# this could happen if x is very small and nu is large which eventually results in overflow (-> -Inf)
26+
# we use this routine to generate bessely(nu::Int, x) in the forward direction starting from bessely0, bessely1
27+
# NaN inputs need to be checked before getting to this routine
28+
return isnan(jnum1) ? (-T(Inf), -T(Inf)) : (jnum1, jnu)
2529
end
30+
2631
# backward recurrence relation for besselj and bessely
2732
# outputs both (bessel(x, nu_end), bessel(x, nu_end-1)
2833
# x = 0.1; j10 = besselj(10, x); j11 = besselj(11, x);

test/bessely_test.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ for v in nu, xx in x
8989
@test isapprox(Bessels.besseljy_positive_args(v, xx)[2], SpecialFunctions.bessely(v, xx), rtol=5e-12)
9090
end
9191

92+
# test limits for small arguments see https://github.com/JuliaMath/Bessels.jl/issues/35
93+
@test bessely(185.0, 1.01) == -Inf
94+
@test bessely(185.5, 1.01) == -Inf
95+
@test bessely(2.0, 1e-300) == -Inf
96+
@test bessely(4.0, 1e-80) == -Inf
97+
@test bessely(4.5, 1e-80) == -Inf
98+
9299
# need to test accuracy of negative orders and negative arguments and all combinations within
93100
# SpecialFunctions.jl doesn't provide these so will hand check against hard values
94101
# values taken from https://keisan.casio.com/exec/system/1180573474 which match mathematica

0 commit comments

Comments
 (0)