@@ -237,11 +237,9 @@ nu and x must be real where nu and x can be positive or negative.
237
237
"""
238
238
bessely (nu:: Real , x:: Real ) = _bessely (nu, float (x))
239
239
240
- _bessely (nu, x:: Float32 ) = Float32 (_bessely (nu, Float64 (x)))
241
-
242
240
_bessely (nu, x:: Float16 ) = Float16 (_bessely (nu, Float32 (x)))
243
241
244
- function _bessely (nu, x:: T ) where T <: Float64
242
+ function _bessely (nu, x:: T ) where T <: Union{Float32, Float64}
245
243
isnan (nu) || isnan (x) && return NaN
246
244
isinteger (nu) && return _bessely (Int (nu), x)
247
245
abs_nu = abs (nu)
@@ -250,7 +248,7 @@ function _bessely(nu, x::T) where T <: Float64
250
248
Ynu = bessely_positive_args (abs_nu, abs_x)
251
249
if nu >= zero (T)
252
250
if x >= zero (T)
253
- return Ynu
251
+ return T ( Ynu)
254
252
else
255
253
return throw (DomainError (x, " Complex result returned for real arguments. Complex arguments are currently not supported" ))
256
254
# 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
259
257
Jnu = besselj_positive_args (abs_nu, abs_x)
260
258
spi, cpi = sincospi (abs_nu)
261
259
if x >= zero (T)
262
- return Ynu * cpi + Jnu * spi
260
+ return T ( Ynu * cpi + Jnu * spi)
263
261
else
264
262
return throw (DomainError (x, " Complex result returned for real arguments. Complex arguments are currently not supported" ))
265
263
# return cpi * (Ynu * cispi(nu) + 2im * Jnu * cpi) + Jnu * spi * cispi(abs_nu)
266
264
end
267
265
end
268
266
end
269
267
270
- function _bessely (nu:: Integer , x:: T ) where T <: Float64
268
+ function _bessely (nu:: Integer , x:: T ) where T <: Union{Float32, Float64}
271
269
abs_nu = abs (nu)
272
270
abs_x = abs (x)
273
271
sg = iseven (abs_nu) ? 1 : - 1
274
272
275
273
Ynu = bessely_positive_args (abs_nu, abs_x)
276
274
if nu >= zero (T)
277
275
if x >= zero (T)
278
- return Ynu
276
+ return T ( Ynu)
279
277
else
280
278
return throw (DomainError (x, " Complex result returned for real arguments. Complex arguments are currently not supported" ))
281
279
# return Ynu * sg + 2im * sg * besselj_positive_args(abs_nu, abs_x)
282
280
end
283
281
else
284
282
if x >= zero (T)
285
- return Ynu * sg
283
+ return T ( Ynu * sg)
286
284
else
287
285
return throw (DomainError (x, " Complex result returned for real arguments. Complex arguments are currently not supported" ))
288
286
# return Ynu + 2im * besselj_positive_args(abs_nu, abs_x)
@@ -320,14 +318,7 @@ function bessely_positive_args(nu, x::T) where T
320
318
# use power series for small x and for when nu > x
321
319
bessely_series_cutoff (nu, x) && return bessely_power_series (nu, x)[1 ]
322
320
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)
331
322
end
332
323
333
324
# ####
@@ -354,27 +345,48 @@ Outpus both (Y_{nu}(x), J_{nu}(x)).
354
345
"""
355
346
function bessely_power_series (v, x:: T ) where T
356
347
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)
359
353
a = (x/ 2 )^ v
360
354
# check for underflow and return limit for small arguments
361
355
iszero (a) && return (- T (Inf ), a)
362
356
363
357
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 ))
366
360
t2 = (x/ 2 )^ 2
367
361
for i in 0 : MaxIter
368
362
out += a
369
363
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
373
367
end
374
368
s, c = sincospi (v)
375
369
return (out* c - out2) / s, out
376
370
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
378
390
379
391
# ####
380
392
# #### Chebyshev approximation for Y_{nu}(x)
0 commit comments