@@ -150,3 +150,186 @@ function besselj1(x::Float32)
150
150
return p * s
151
151
end
152
152
end
153
+ """
154
+ besselj(nu, x::T) where T <: Union{Float32, Float64}
155
+
156
+ Bessel function of the first kind of order nu, ``J_{nu}(x)``.
157
+ Nu must be real.
158
+ """
159
+ function _besselj (nu, x)
160
+ nu == 0 && return besselj0 (x)
161
+ nu == 1 && return besselj1 (x)
162
+
163
+ x < 4.0 && return besselj_small_arguments_orders (nu, x)
164
+
165
+ large_arg_cutoff = 1.65 * nu
166
+ (x > large_arg_cutoff && x > 20.0 ) && return besselj_large_argument (nu, x)
167
+
168
+
169
+ debye_cutoff = 2.0 + 1.00035 * x + (302.681 * x)^ (1 / 3 )
170
+ nu > debye_cutoff && return besselj_debye (nu, x)
171
+
172
+ if nu >= x
173
+ nu_shift = ceil (Int, 5.2 + 1.00033 * x + (1427.61 * x)^ (1 / 3 ) - nu)
174
+ v = nu + nu_shift
175
+ arr = range (v, stop = nu, length = nu_shift + 1 )
176
+ jnu = besselj_debye (v, x)
177
+ jnup1 = besselj_debye (v+ 1 , x)
178
+ return besselj_down_recurrence (x, jnu, jnup1, arr)[2 ]
179
+ end
180
+
181
+ # at this point x > nu and x < nu * 1.65
182
+ # in this region forward recurrence is stable
183
+ # we must decide if we should do backward recurrence if we are closer to debye accuracy
184
+ # or if we should do forward recurrence if we are closer to large argument expansion
185
+ debye_cutoff = 5.0 + 1.00033 * x + (1427.61 * x)^ (1 / 3 )
186
+
187
+ debye_diff = debye_cutoff - nu
188
+ large_arg_diff = nu - x / 2.0
189
+
190
+ if (debye_diff > large_arg_diff && x > 20.0 )
191
+ nu_shift = ceil (large_arg_diff)
192
+ v2 = nu - nu_shift
193
+ jnu = besselj_large_argument (v2, x)
194
+ jnum1 = besselj_large_argument (v2 - 1 , x)
195
+ return besselj_up_recurrence (x, jnu, jnum1, v2, nu)[2 ]
196
+ else
197
+ nu_shift = ceil (Int, debye_diff)
198
+ v = nu + nu_shift
199
+ arr = range (v, stop = nu, length = nu_shift + 1 )
200
+ jnu = besselj_debye (v, x)
201
+ jnup1 = besselj_debye (v+ 1 , x)
202
+ return besselj_down_recurrence (x, jnu, jnup1, arr)[2 ]
203
+ end
204
+ end
205
+
206
+ # for moderate size arguments of x and v this has relative errors ~9e-15
207
+ # for large arguments relative errors ~1e-13
208
+ function besselj_large_argument (v, x:: T ) where T
209
+ α, αp = _α_αp_asymptotic (v, x)
210
+ b = SQ2OPI (T) / sqrt (αp * x)
211
+
212
+ S, C = sincos (PIO2 (T)* v)
213
+ Sα, Cα = sincos (α)
214
+ s1 = (C - S) * Cα
215
+ s2 = (C + S) * Sα
216
+
217
+ return SQ2O2 (T) * (s1 + s2) * b
218
+ end
219
+
220
+ # generally can only use for x < 4.0
221
+ # this needs a better way to sum these as it produces large errors
222
+ # only valid in non-oscillatory regime (v>1/2, 0<t<sqrt(v^2 - 0.25))
223
+ # power series has premature underflow for large orders
224
+ function besselj_small_arguments_orders (v, x:: T ) where T
225
+ v > 60 && return log_besselj_small_arguments_orders (v, x)
226
+
227
+ MaxIter = 2000
228
+ out = zero (T)
229
+ a = (x/ 2 )^ v / gamma (v + one (T))
230
+ t2 = (x/ 2 )^ 2
231
+ for i in 0 : MaxIter
232
+ out += a
233
+ abs (a) < eps (T) * abs (out) && break
234
+ a *= - inv ((v + i + one (T)) * (i + one (T))) * t2
235
+ end
236
+ return out
237
+ end
238
+
239
+ # this needs a better way to sum these as it produces large errors
240
+ # use when v is large and x is small
241
+ # need for bessely
242
+ function log_besselj_small_arguments_orders (v, x:: T ) where T
243
+ MaxIter = 2000
244
+ out = zero (T)
245
+ a = one (T)
246
+ x2 = (x/ 2 )^ 2
247
+ for i in 0 : MaxIter
248
+ out += a
249
+ a *= - x2 * inv ((i + one (T)) * (v + i + one (T)))
250
+ (abs (a) < eps (T) * abs (out)) && break
251
+ end
252
+ logout = - loggamma (v + 1 ) + fma (v, log (x/ 2 ), log (out))
253
+ return exp (logout)
254
+ end
255
+
256
+ # valid when x < v (uniform asymptotic expansions)
257
+ function besselj_debye (v, x)
258
+ T = eltype (x)
259
+ S = promote_type (T, Float64)
260
+ x = S (x)
261
+
262
+ vmx = (v + x) * (v - x)
263
+ vs = sqrt (vmx)
264
+ n = muladd (v, - log (x / (v + vs)), - vs)
265
+
266
+ coef = SQ1O2PI (S) * exp (- n) / sqrt (vs)
267
+ p = v / vs
268
+ p2 = v^ 2 / vmx
269
+
270
+ return coef * Uk_poly_Jn (p, v, p2, x, T)
271
+ end
272
+
273
+ # For 0.0 <= x < 171.5
274
+ # Mean ULP = 0.55
275
+ # Max ULP = 2.4
276
+ # Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
277
+ function gamma (x)
278
+ if x > 11.5
279
+ return large_gamma (x)
280
+ elseif x < 0.0
281
+ # p = floor(x)
282
+ # isequal(p, abs(x)) && return throw(DomainError(x, "NaN result for non-NaN input."))
283
+ # need reflection formula
284
+ return throw (DomainError (x, " Negative numbers are currently not implemented" ))
285
+ elseif x <= 11.5
286
+ return small_gamma (x)
287
+ elseif isnan (x)
288
+ return x
289
+ end
290
+ end
291
+ function large_gamma (x)
292
+ isinf (x) && return x
293
+ T = Float64
294
+ w = inv (x)
295
+ s = (
296
+ 8.333333333333331800504e-2 , 3.472222222230075327854e-3 , - 2.681327161876304418288e-3 , - 2.294719747873185405699e-4 ,
297
+ 7.840334842744753003862e-4 , 6.989332260623193171870e-5 , - 5.950237554056330156018e-4 , - 2.363848809501759061727e-5 ,
298
+ 7.147391378143610789273e-4
299
+ )
300
+ w = w * evalpoly (w, s) + one (T)
301
+ # lose precision on following block
302
+ y = exp ((x))
303
+ # avoid overflow
304
+ v = x^ (0.5 * x - 0.25 )
305
+ y = v * (v / y)
306
+
307
+ return SQ2PI (T) * y * w
308
+ end
309
+ function small_gamma (x)
310
+ T = Float64
311
+ P = (
312
+ 1.000000000000000000009e0 , 8.378004301573126728826e-1 , 3.629515436640239168939e-1 , 1.113062816019361559013e-1 ,
313
+ 2.385363243461108252554e-2 , 4.092666828394035500949e-3 , 4.542931960608009155600e-4 , 4.212760487471622013093e-5
314
+ )
315
+ Q = (
316
+ 9.999999999999999999908e-1 , 4.150160950588455434583e-1 , - 2.243510905670329164562e-1 , - 4.633887671244534213831e-2 ,
317
+ 2.773706565840072979165e-2 , - 7.955933682494738320586e-4 , - 1.237799246653152231188e-3 , 2.346584059160635244282e-4 ,
318
+ - 1.397148517476170440917e-5
319
+ )
320
+
321
+ z = one (T)
322
+ while x >= 3.0
323
+ x -= one (T)
324
+ z *= x
325
+ end
326
+ while x < 2.0
327
+ z /= x
328
+ x += one (T)
329
+ end
330
+
331
+ x -= T (2 )
332
+ p = evalpoly (x, P)
333
+ q = evalpoly (x, Q)
334
+ return z * p / q
335
+ end
0 commit comments