@@ -150,6 +150,29 @@ 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
+ if x < 30.0
163
+ if nu > 60.0
164
+ return log_besselj_small_arguments_orders (nu, x)
165
+ else
166
+ return besselj_small_arguments_orders (nu, x)
167
+ end
168
+ elseif 2 * x < nu
169
+ return besselj_debye (nu, x)
170
+ elseif x > 2 * nu
171
+ return besselj_large_argument (nu, x)
172
+ else
173
+ return nothing
174
+ end
175
+ end
153
176
154
177
function _α_αp_asymptotic (v, x:: T ) where T
155
178
μ = 4 * v^ 2
@@ -190,8 +213,9 @@ function bessely_large_argument(v, x::T) where T
190
213
return sin (α)* b
191
214
end
192
215
193
-
216
+ # this needs a better way to sum these as it produces large errors
194
217
# only valid in non-oscillatory regime (v>1/2, 0<t<sqrt(v^2 - 0.25))
218
+ # power series has premature underflow for large orders
195
219
function besselj_small_arguments_orders (v, x:: T ) where T
196
220
MaxIter = 1_000
197
221
out = zero (T)
@@ -200,33 +224,35 @@ function besselj_small_arguments_orders(v, x::T) where T
200
224
for i in 0 : MaxIter
201
225
out += a
202
226
abs (a) < eps (T) * abs (out) && break
203
- a = - a * inv ((v + i + one (T)) * (i + one (T))) * t2
227
+ a * = - inv ((v + i + one (T)) * (i + one (T))) * t2
204
228
end
205
229
return out
206
230
end
207
231
232
+ # this needs a better way to sum these as it produces large errors
208
233
# perhaps use when v is small i believe v also has to be positive for this to work
209
234
# need for bessely
210
235
function log_besselj_small_arguments_orders (v, x:: T ) where T
211
- MaxIter = 200
236
+ MaxIter = 500
212
237
out = zero (T)
213
238
a = one (T)
214
239
x2 = (x/ 2 )^ 2
215
240
for i in 0 : MaxIter
216
241
out += a
217
242
a = - a * x2 * inv ((i + one (T)) * (v + i + one (T)))
218
- # (abs(a) < eps(T) * abs(out)) && break
243
+ (abs (a) < eps (T) * abs (out)) && break
219
244
end
220
- logout = - loggamma (v + 1 ) + v * log (x/ 2 ) + log (out)
221
- return logout
245
+ @show out
246
+ logout = - loggamma (v + 1 ) + fma (v, log (x/ 2 ), log (out))
247
+ return exp (logout)
222
248
end
223
249
224
250
# valid when x < v (uniform asymptotic expansions)
225
251
function besselj_debye (v, x)
226
252
T = eltype (x)
227
253
S = promote_type (T, Float64)
228
254
x = S (x)
229
-
255
+
230
256
vmx = fma (v,v, - x^ 2 )
231
257
vdx = v/ x
232
258
b = sqrt (vmx)
@@ -238,3 +264,71 @@ function besselj_debye(v, x)
238
264
239
265
return coef * Uk_poly_Jn (p, v, p2, T)
240
266
end
267
+
268
+ # For 0.0 <= x < 171.5
269
+ # Mean ULP = 0.55
270
+ # Max ULP = 2.4
271
+ # Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
272
+ function gamma (x)
273
+ if x > 11.5
274
+ return large_gamma (x)
275
+ elseif x < 0.0
276
+ # p = floor(x)
277
+ # isequal(p, abs(x)) && return throw(DomainError(x, "NaN result for non-NaN input."))
278
+ # need reflection formula
279
+ return throw (DomainError (x, " Negative numbers are currently not implemented" ))
280
+ elseif x <= 11.5
281
+ return small_gamma (x)
282
+ elseif isnan (x)
283
+ return x
284
+ end
285
+ end
286
+ function large_gamma (x)
287
+ T = Float64
288
+ w = inv (x)
289
+ s = (
290
+ 8.333333333333331800504e-2 , 3.472222222230075327854e-3 , - 2.681327161876304418288e-3 , - 2.294719747873185405699e-4 ,
291
+ 7.840334842744753003862e-4 , 6.989332260623193171870e-5 , - 5.950237554056330156018e-4 , - 2.363848809501759061727e-5 ,
292
+ 7.147391378143610789273e-4
293
+ )
294
+ w = w * evalpoly (w, s) + one (T)
295
+ # lose precision on following block
296
+ y = exp ((x))
297
+ if x > 143.01608
298
+ isinf (x) && return x
299
+ # avoid overflow
300
+ v = x^ (0.5 * x - 0.25 )
301
+ y = v * (v / y)
302
+ else
303
+ y = x^ (x - 0.5 ) / y
304
+ # (x - 0.5) * log(x) - x
305
+ end
306
+ return SQ2PI (T) * y * w
307
+ end
308
+ function small_gamma (x)
309
+ T = Float64
310
+ P = (
311
+ 1.000000000000000000009e0 , 8.378004301573126728826e-1 , 3.629515436640239168939e-1 , 1.113062816019361559013e-1 ,
312
+ 2.385363243461108252554e-2 , 4.092666828394035500949e-3 , 4.542931960608009155600e-4 , 4.212760487471622013093e-5
313
+ )
314
+ Q = (
315
+ 9.999999999999999999908e-1 , 4.150160950588455434583e-1 , - 2.243510905670329164562e-1 , - 4.633887671244534213831e-2 ,
316
+ 2.773706565840072979165e-2 , - 7.955933682494738320586e-4 , - 1.237799246653152231188e-3 , 2.346584059160635244282e-4 ,
317
+ - 1.397148517476170440917e-5
318
+ )
319
+
320
+ z = one (T)
321
+ while x >= 3.0
322
+ x -= one (T)
323
+ z *= x
324
+ end
325
+ while x < 2.0
326
+ z /= x
327
+ x += one (T)
328
+ end
329
+
330
+ x -= T (2 )
331
+ p = evalpoly (x, P)
332
+ q = evalpoly (x, Q)
333
+ return z * p / q
334
+ end
0 commit comments