41
41
# K_{nu+1} = (2*nu/x)*K_{nu} + K_{nu-1}
42
42
#
43
43
# When nu is large, a large amount of recurrence is necesary.
44
- # At this point as nu -> Inf it is more efficient to use a uniform expansion.
45
- # The boundary of the expansion depends on the accuracy required.
46
- # For more information see [4]. This approach is not yet implemented, so recurrence
47
- # is used for all values of nu.
48
- #
49
- #
44
+ # We consider uniform asymptotic expansion for large orders to more efficiently
45
+ # compute besselk(nu, x) when nu is larger than 100 (Let's double check this cutoff)
46
+ # The boundary should be carefully determined for accuracy and machine roundoff.
47
+ # We use 10.41.4 from the Digital Library of Math Functions [5].
48
+ # This is also 9.7.8 in Abramowitz and Stegun [6].
49
+ # The U polynomials are the most tricky. They are listed up to order 4 in Table 9.39
50
+ # of [6]. For Float32, >=4 U polynomials are usually necessary. For Float64 values,
51
+ # >= 8 orders are needed. However, this largely depends on the cutoff of order you need.
52
+ # For moderatelly sized orders (nu=50), might need 11-12 orders to reach good enough accuracy
53
+ # in double precision.
54
+ #
55
+ # However, calculation of these higher order U polynomials are tedious. These have been hand
56
+ # calculated and somewhat crosschecked with symbolic math. There could be errors. They are listed
57
+ # here as a reference as higher orders are impossible to find and needed for any meaningfully accurate calculation.
58
+
59
+ # u0 = one(x)
60
+ # u1 = p / 24 * (3 - 5*p^2) * -1 / v
61
+ # u2 = p^2 / 1152 * (81 - 462*p^2 + 385*p^4) / v^2
62
+ # u3 = p^3 / 414720 * (30375 - 369603 * p^2 + 765765*p^4 - 425425*p^6) * -1 / v^3
63
+ # u4 = p^4 / 39813120 * (4465125 - 94121676*p^2 + 349922430*p^4 - 446185740*p^6 + 185910725*p^8) / v^4
64
+ # u5 = p^5 / 6688604160 * (-188699385875*p^10 + 566098157625*p^8 - 614135872350*p^6 + 284499769554*p^4 - 49286948607*p^2 + 1519035525) * -1 / v^5
65
+ # u6 = p^6 / 4815794995200 * (1023694168371875*p^12 - 3685299006138750*p^10 + 5104696716244125*p^8 - 3369032068261860*p^6
66
+ # + 1050760774457901*p^4 - 127577298354750*p^2 + 2757049477875) * 1 / v^6
67
+ # u7 = p^7 / 115579079884800 * (-221849150488590625*p^14 + 931766432052080625*p^12 - 1570320948552481125*p^10 + 1347119637570231525*p^8
68
+ # - 613221795981706275*p^6 + 138799253740521843*p^4 - 12493049053044375*p^2 + 199689155040375) * -1 / v^7
69
+ # u8 = p^8 / 22191183337881600 * (448357133137441653125*p^16 - 2152114239059719935000*p^14 + 4272845805510421639500*p^12 - 4513690624987320777000*p^10
70
+ # + 2711772922412520971550*p^8 - 914113758588905038248*p^6 + 157768535329832893644*p^4 - 10960565081605263000*p^2 + 134790179652253125) * 1 / v^8
71
+ # u9 = p^9 / 263631258054033408000 * (-64041091111686478524109375*p^18 + 345821892003106984030190625*p^16 - 790370708270219620781737500*p^14
72
+ # + 992115946599792610768672500*p^12 - 741743213039573443221773250*p^10 + 334380732677827878090447630*p^8 - 87432034049652400520788332*p^6
73
+ # + 11921080954211358275362500*p^4 - 659033454841709672064375*p^2 + 6427469716717690265625) * -1 / v^9
74
+ # u10 = p^10 / 88580102706155225088000 * (290938676920391671935028890625*p^20 - 1745632061522350031610173343750*p^18 + 4513386761946134740461797128125*p^16
75
+ # - 6564241639632418015173104205000*p^14 + 5876803711285273203043452095250*p^12 - 3327704366990695147540934069220*p^10 + 1177120360439828012193658602930*p^8
76
+ # - 246750339886026017414509498824*p^6 + 27299183373230345667273718125*p^4 - 1230031256571145165088463750*p^2 + 9745329584487361980740625) * 1 / v^10
77
+ #
78
+ # For large orders these formulas will converge much faster than using upward recurrence.
79
+ # If using up to the fifth U polynomial, it requires evaluation of a 15 degree polynomial.
80
+ # For tenth U polynomial, it requires evaluation of a 30 degree polynomial.
81
+ #
82
+ #
50
83
# [1] "Rational Approximations for the Modified Bessel Function of the Second Kind
51
84
# - K0(x) for Computations with Double Precision" by Pavel Holoborodko
52
85
# [2] "Rational Approximations for the Modified Bessel Function of the Second Kind
53
86
# - K1(x) for Computations with Double Precision" by Pavel Holoborodko
54
87
# [3] https://github.com/boostorg/math/tree/develop/include/boost/math/special_functions/detail
55
- # [4] "Computation of Bessel Functions of Complex Argument and Large ORder " by Donald E. Amos
88
+ # [4] "Computation of Bessel Functions of Complex Argument and Large Order " by Donald E. Amos
56
89
# Sandia National Laboratories
90
+ # [5] https://dlmf.nist.gov/10.41
91
+ # [6] Abramowitz, Milton, and Irene A. Stegun, eds. Handbook of mathematical functions with formulas, graphs, and mathematical tables.
92
+ # Vol. 55. US Government printing office, 1964.
57
93
#
58
94
"""
59
95
besselk0(x::T) where T <: Union{Float32, Float64}
@@ -130,14 +166,12 @@ function besselk1x(x::T) where T <: Union{Float32, Float64}
130
166
end
131
167
end
132
168
#=
133
- Recurrence is used for all values of nu. If besselk0(x) or besselk1(0) is equal to zero
169
+ If besselk0(x) or besselk1(0) is equal to zero
134
170
this will underflow and always return zero even if besselk(x, nu)
135
171
is larger than the smallest representing floating point value.
136
172
In other words, for large values of x and small to moderate values of nu,
137
173
this routine will underflow to zero.
138
174
For small to medium values of x and large values of nu this will overflow and return Inf.
139
-
140
- In the future, a more efficient algorithm for large nu should be incorporated.
141
175
=#
142
176
"""
143
177
besselk(x::T) where T <: Union{Float32, Float64}
@@ -148,7 +182,7 @@ function besselk(nu::Int, x::T) where T <: Union{Float32, Float64}
148
182
if nu < 100
149
183
return three_term_recurrence (x, besselk0 (x), besselk1 (x), nu)
150
184
else
151
- return k1 (BigFloat (nu), BigFloat (x))
185
+ return besselk_large_orders (BigFloat (nu), BigFloat (x))
152
186
end
153
187
end
154
188
"""
179
213
end
180
214
181
215
182
- function k1 (v, x:: T ) where T <: AbstractFloat
216
+ function besselk_large_orders (v, x:: T ) where T <: AbstractFloat
183
217
z = x / v
184
218
zs = sqrt (1 + z^ 2 )
185
219
0 commit comments