@@ -233,7 +233,7 @@ function besselk_positive_args(nu, x::T) where T <: Union{Float32, Float64}
233
233
(isinteger (nu- 1 / 2 ) && ! debye_cut) && return sphericalbesselk (nu- 1 / 2 , x)* SQRT_PID2 (T)* sqrt (x)
234
234
235
235
# check if the standard asymptotic expansion can be used:
236
- besselk_asexp_cutoff (nu, x) && return besselk_asymptoticexp (nu, x, 10 )
236
+ besselk_asexp_cutoff (nu, x) && return besselk_large_argument (nu, x)
237
237
238
238
# use uniform debye expansion if x or nu is large
239
239
debye_cut && return besselk_large_orders (nu, x)
@@ -442,55 +442,28 @@ Computes the asymptotic expansion of K_ν w.r.t. argument. Accurate for large x,
442
442
"""
443
443
besselk_asexp_cutoff (nu, x:: T ) where T = (nu < 20.0 ) && (x > ASEXP_CUTOFF (T))
444
444
445
- # Compute the function for (_v, _v+1), where _v = v-floor(v), and then do
446
- # forward recursion. If the argument is really large, this should be faster than
447
- # the uniform asymptotic expansion and plenty accurate.
448
- function besselk_asymptoticexp (v, x:: T , order) where T
449
- _v = v - floor (v)
450
- (kv, kvp1) = _besselk_as_pair (_v, x, order)
451
- v == _v && return kv
452
- _v += one (v)
453
- twodx = T (2 )* inv (x)
454
- while _v < v
455
- (kv, kvp1) = (kvp1, muladd (kvp1, twodx* _v, kv))
456
- _v += one (_v)
457
- end
458
- kvp1
445
+ function besselk_large_argument (v, x:: T ) where T
446
+ a = exp (- x / 2 )
447
+ coef = a * sqrt (pi / 2 x)
448
+ return T (_besselk_large_argument (v, x) * coef * a)
459
449
end
460
450
461
- # For now, no exponential improvement. It requires the exponential integral
462
- # function, which would either need to be lifted from SpecialFunctions.jl or
463
- # re-implemented. And with an order of, like, 10, this seems to be pretty
464
- # accurate and still faster than the uniform asymptotic expansion.
465
- function _besselk_as_pair (v, x:: T , order) where T
466
- fv = 4 * v* v
467
- fvp1 = 4 * (v+ one (v))^ 2
468
- _z = x
469
- ser_v = one (T)
470
- ser_vp1 = one (T)
471
- floatj = one (T)
472
- ak_numv = fv - floatj
473
- ak_numvp1 = fvp1 - floatj
474
- factj = one (T)
475
- twofloatj = one (T)
476
- eightj = T (8 )
477
- for _ in 1 : order
478
- # add to the series:
479
- term_v = ak_numv/ (factj* _z* eightj)
480
- ser_v += term_v
481
- term_vp1 = ak_numvp1/ (factj* _z* eightj)
482
- ser_vp1 += term_vp1
483
- # update ak and _z:
484
- floatj += one (T)
485
- twofloatj += T (2 )
486
- factj *= floatj
487
- fourfloatj = twofloatj* twofloatj
488
- ak_numv *= (fv - fourfloatj)
489
- ak_numvp1 *= (fvp1 - fourfloatj)
490
- _z *= x
491
- eightj *= T (8 )
492
- end
493
- pre_multiply = SQRT_PID2 (T)* exp (- x)/ sqrt (x)
494
- (pre_multiply* ser_v, pre_multiply* ser_vp1)
451
+ besselk_large_argument_scaled (v, x:: T ) where T = T (_besselk_large_argument (v, x) * sqrt (pi / 2 x))
452
+
453
+ function _besselk_large_argument (v, x:: T ) where T
454
+ MaxIter = 5000
455
+ S = promote_type (T, Float64)
456
+ v, x = S (v), S (x)
457
+
458
+ fv2 = 4 * v^ 2
459
+ term = one (S)
460
+ res = term
461
+ s = term
462
+ for i in 1 : MaxIter
463
+ offset = muladd (2 , i, - 1 )
464
+ term *= muladd (offset, - offset, fv2) / (8 * x * i)
465
+ res = muladd (term, s, res)
466
+ abs (term) <= eps (T) && break
467
+ end
468
+ return res
495
469
end
496
-
0 commit comments