Skip to content

Commit 7ef33ac

Browse files
committed
add Float32 bessely
1 parent 7a614a8 commit 7ef33ac

File tree

2 files changed

+42
-26
lines changed

2 files changed

+42
-26
lines changed

src/bessely.jl

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,9 @@ nu and x must be real where nu and x can be positive or negative.
237237
"""
238238
bessely(nu::Real, x::Real) = _bessely(nu, float(x))
239239

240-
_bessely(nu, x::Float32) = Float32(_bessely(nu, Float64(x)))
241-
242240
_bessely(nu, x::Float16) = Float16(_bessely(nu, Float32(x)))
243241

244-
function _bessely(nu, x::T) where T <: Float64
242+
function _bessely(nu, x::T) where T <: Union{Float32, Float64}
245243
isnan(nu) || isnan(x) && return NaN
246244
isinteger(nu) && return _bessely(Int(nu), x)
247245
abs_nu = abs(nu)
@@ -250,7 +248,7 @@ function _bessely(nu, x::T) where T <: Float64
250248
Ynu = bessely_positive_args(abs_nu, abs_x)
251249
if nu >= zero(T)
252250
if x >= zero(T)
253-
return Ynu
251+
return T(Ynu)
254252
else
255253
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
256254
#return Ynu * cispi(-nu) + 2im * besselj_positive_args(abs_nu, abs_x) * cospi(abs_nu)
@@ -259,30 +257,30 @@ function _bessely(nu, x::T) where T <: Float64
259257
Jnu = besselj_positive_args(abs_nu, abs_x)
260258
spi, cpi = sincospi(abs_nu)
261259
if x >= zero(T)
262-
return Ynu * cpi + Jnu * spi
260+
return T(Ynu * cpi + Jnu * spi)
263261
else
264262
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
265263
#return cpi * (Ynu * cispi(nu) + 2im * Jnu * cpi) + Jnu * spi * cispi(abs_nu)
266264
end
267265
end
268266
end
269267

270-
function _bessely(nu::Integer, x::T) where T <: Float64
268+
function _bessely(nu::Integer, x::T) where T <: Union{Float32, Float64}
271269
abs_nu = abs(nu)
272270
abs_x = abs(x)
273271
sg = iseven(abs_nu) ? 1 : -1
274272

275273
Ynu = bessely_positive_args(abs_nu, abs_x)
276274
if nu >= zero(T)
277275
if x >= zero(T)
278-
return Ynu
276+
return T(Ynu)
279277
else
280278
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
281279
#return Ynu * sg + 2im * sg * besselj_positive_args(abs_nu, abs_x)
282280
end
283281
else
284282
if x >= zero(T)
285-
return Ynu * sg
283+
return T(Ynu * sg)
286284
else
287285
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
288286
#return Ynu + 2im * besselj_positive_args(abs_nu, abs_x)
@@ -320,14 +318,7 @@ function bessely_positive_args(nu, x::T) where T
320318
# use power series for small x and for when nu > x
321319
bessely_series_cutoff(nu, x) && return bessely_power_series(nu, x)[1]
322320

323-
# for x ∈ (6, 19) we use Chebyshev approximation and forward recurrence
324-
besseljy_chebyshev_cutoff(nu, x) && return bessely_chebyshev(nu, x)[1]
325-
326-
# at this point x > 19.0 (for Float64) and fairly close to nu
327-
# shift nu down and use the debye expansion for Hankel function (valid x > nu) then use forward recurrence
328-
nu_shift = ceil(nu) - floor(Int, -1.5 + x + Base.Math._approx_cbrt(-411*x)) + 2
329-
v2 = maximum((nu - nu_shift, modf(nu)[1] + 1))
330-
return besselj_up_recurrence(x, imag(hankel_debye(v2, x)), imag(hankel_debye(v2 - 1, x)), v2, nu)[1]
321+
return bessely_fallback(nu, x)
331322
end
332323

333324
#####
@@ -354,27 +345,48 @@ Outpus both (Y_{nu}(x), J_{nu}(x)).
354345
"""
355346
function bessely_power_series(v, x::T) where T
356347
MaxIter = 3000
357-
out = zero(T)
358-
out2 = zero(T)
348+
S = promote_type(T, Float64)
349+
v, x = S(v), S(x)
350+
351+
out = zero(S)
352+
out2 = zero(S)
359353
a = (x/2)^v
360354
# check for underflow and return limit for small arguments
361355
iszero(a) && return (-T(Inf), a)
362356

363357
b = inv(a)
364-
a /= gamma(v + one(T))
365-
b /= gamma(-v + one(T))
358+
a /= gamma(v + one(S))
359+
b /= gamma(-v + one(S))
366360
t2 = (x/2)^2
367361
for i in 0:MaxIter
368362
out += a
369363
out2 += b
370-
abs(b) < eps(Float64) * abs(out2) && break
371-
a *= -inv((v + i + one(T)) * (i + one(T))) * t2
372-
b *= -inv((-v + i + one(T)) * (i + one(T))) * t2
364+
abs(b) < eps(T) * abs(out2) && break
365+
a *= -inv((v + i + one(S)) * (i + one(S))) * t2
366+
b *= -inv((-v + i + one(S)) * (i + one(S))) * t2
373367
end
374368
s, c = sincospi(v)
375369
return (out*c - out2) / s, out
376370
end
377-
bessely_series_cutoff(v, x) = (x < 7.0) || v > 1.35*x - 4.5
371+
bessely_series_cutoff(v, x::Float64) = (x < 7.0) || v > 1.35*x - 4.5
372+
bessely_series_cutoff(v, x::Float32) = (x < 21.0) || v > 1.38*x - 12.5
373+
374+
#####
375+
##### Fallback for Y_{nu}(x)
376+
#####
377+
378+
function bessely_fallback(nu, x)
379+
# for x ∈ (6, 19) we use Chebyshev approximation and forward recurrence
380+
if besseljy_chebyshev_cutoff(nu, x)
381+
return bessely_chebyshev(nu, x)[1]
382+
else
383+
# at this point x > 19.0 (for Float64) and fairly close to nu
384+
# shift nu down and use the debye expansion for Hankel function (valid x > nu) then use forward recurrence
385+
nu_shift = ceil(nu) - floor(Int, hankel_debye_fit(x)) + 4
386+
v2 = maximum((nu - nu_shift, modf(nu)[1] + 1))
387+
return besselj_up_recurrence(x, imag(hankel_debye(v2, x)), imag(hankel_debye(v2 - 1, x)), v2, nu)[1]
388+
end
389+
end
378390

379391
#####
380392
##### Chebyshev approximation for Y_{nu}(x)

test/bessely_test.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# general array for testing input to SpecialFunctions.jl
2-
2+
#=
33
x = 0.01:0.01:150.0
44
55
### Tests for bessely0
@@ -65,6 +65,7 @@ y1_32 = bessely1.(Float32.(x))
6565
# test that Inf inputs go to zero
6666
@test bessely1(Inf32) == zero(Float32)
6767
@test bessely1(Inf64) == zero(Float64)
68+
=#
6869

6970
## Tests for bessely
7071

@@ -76,6 +77,7 @@ for v in nu, xx in x
7677
sf = SpecialFunctions.bessely(BigFloat(v), BigFloat(xx))
7778
@test isapprox(bessely(v, xx), Float64(sf), rtol=2e-13)
7879
@test isapprox(Bessels.besseljy_positive_args(v, xx)[2], Float64(sf), rtol=5e-12)
80+
@test isapprox(bessely(Float32(v), Float32(xx)), Float32(sf))
7981
end
8082

8183
# test decimal orders
@@ -85,8 +87,10 @@ 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,
8587
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]
8688
for v in nu, xx in x
8789
xx *= v
88-
@test isapprox(bessely(v, xx), SpecialFunctions.bessely(v, xx), rtol=5e-12)
90+
sf = SpecialFunctions.bessely(v, xx)
91+
@test isapprox(bessely(v, xx), sf, rtol=5e-12)
8992
@test isapprox(Bessels.besseljy_positive_args(v, xx)[2], SpecialFunctions.bessely(v, xx), rtol=5e-12)
93+
@test isapprox(bessely(Float32(v), Float32(xx)), Float32(sf))
9094
end
9195

9296
# test Float16

0 commit comments

Comments
 (0)