216
216
airyai_power_series_cutoff (x:: T , y:: T ) where T <: Float64 = x < 2 && abs (y) > - 1.4 * (x + 5.5 )
217
217
airyai_power_series_cutoff (x:: T , y:: T ) where T <: Float32 = x < 4.5f0 && abs (y) > - 1.4f0 * (x + 9.5f0 )
218
218
219
- function airyai_power_series (x:: ComplexOrReal{T} ) where T
219
+ function airyai_power_series (x:: ComplexOrReal{T} ; tol = eps (T) ) where T
220
220
S = eltype (x)
221
221
iszero (x) && return S (0.3550280538878172 )
222
222
MaxIter = 3000
@@ -230,18 +230,20 @@ function airyai_power_series(x::ComplexOrReal{T}) where T
230
230
for i in 0 : MaxIter
231
231
ai1 += t
232
232
ai2 += t2
233
- abs (t) < eps (T) * abs (ai1) && break
233
+ abs (t) < tol * abs (ai1) && break
234
234
t *= x3 * inv (9 * (i + one (T))* (i + T (2 )/ 3 ))
235
235
t2 *= x3 * inv (9 * (i + one (T))* (i + T (4 )/ 3 ))
236
236
end
237
237
return (ai1* 3 ^ (- T (2 )/ 3 ) - ai2* 3 ^ (- T (4 )/ 3 ))
238
238
end
239
+ airyai_power_series (x:: Float32 ) = Float32 (airyai_power_series (Float64 (x), tol= eps (Float32)))
240
+ airyai_power_series (x:: ComplexF32 ) = ComplexF32 (airyai_power_series (ComplexF64 (x), tol= eps (Float32)))
239
241
240
242
# ####
241
243
# #### Power series for airyaiprime(x)
242
244
# ####
243
245
244
- function airyaiprime_power_series (x:: ComplexOrReal{T} ) where T
246
+ function airyaiprime_power_series (x:: ComplexOrReal{T} ; tol = eps (T) ) where T
245
247
S = eltype (x)
246
248
iszero (x) && return S (- 0.2588194037928068 )
247
249
MaxIter = 3000
@@ -255,25 +257,27 @@ function airyaiprime_power_series(x::ComplexOrReal{T}) where T
255
257
for i in 0 : MaxIter
256
258
ai1 += t
257
259
ai2 += t2
258
- abs (t) < eps (T) * abs (ai1) && break
260
+ abs (t) < tol * abs (ai1) && break
259
261
t *= x3 * inv (9 * (i + one (T))* (i + T (1 )/ 3 ))
260
262
t2 *= x3 * inv (9 * (i + one (T))* (i + T (5 )/ 3 ))
261
263
end
262
264
return - ai1* 3 ^ (- T (1 )/ 3 ) + ai2* 3 ^ (- T (5 )/ 3 )
263
265
end
266
+ airyaiprime_power_series (x:: Float32 ) = Float32 (airyaiprime_power_series (Float64 (x), tol= eps (Float32)))
267
+ airyaiprime_power_series (x:: ComplexF32 ) = ComplexF32 (airyaiprime_power_series (ComplexF64 (x), tol= eps (Float32)))
264
268
265
269
# ####
266
270
# #### Power series for airybi(x)
267
271
# ####
268
272
269
273
# cutoffs for power series valid for both airybi and airybiprime
270
274
# has a more complicated validity as it works well close to positive real line and for small negative arguments also works for angle(z) ~ 2pi/3
271
- # the statements are somewhat complicated but we absolutely want to hit this branch when we can as the other algorithms are 10x slower
275
+ # the statements are somewhat complicated but we want to hit this branch when we can as the other algorithms are 10x slower
272
276
# the Float32 cutoff can be simplified because it overlaps with the large argument expansion so there isn't a need for more complicated statements
273
277
airybi_power_series_cutoff (x:: T , y:: T ) where T <: Float64 = (abs (y) > - 1.4 * (x + 5.5 ) && abs (y) < - 2.2 * (x - 4 )) || (x > zero (T) && abs (y) < 3 )
274
278
airybi_power_series_cutoff (x:: T , y:: T ) where T <: Float32 = abs (complex (x, y)) < 9
275
279
276
- function airybi_power_series (x:: ComplexOrReal{T} ) where T
280
+ function airybi_power_series (x:: ComplexOrReal{T} ; tol = eps (T) ) where T
277
281
S = eltype (x)
278
282
iszero (x) && return S (0.6149266274460007 )
279
283
MaxIter = 3000
@@ -287,18 +291,20 @@ function airybi_power_series(x::ComplexOrReal{T}) where T
287
291
for i in 0 : MaxIter
288
292
ai1 += t
289
293
ai2 += t2
290
- abs (t) < eps (T) * abs (ai1) && break
294
+ abs (t) < tol * abs (ai1) && break
291
295
t *= x3 * inv (9 * (i + one (T))* (i + T (2 )/ 3 ))
292
296
t2 *= x3 * inv (9 * (i + one (T))* (i + T (4 )/ 3 ))
293
297
end
294
298
return (ai1* 3 ^ (- T (1 )/ 6 ) + ai2* 3 ^ (- T (5 )/ 6 ))
295
299
end
300
+ airybi_power_series (x:: Float32 ) = Float32 (airybi_power_series (Float64 (x), tol= eps (Float32)))
301
+ airybi_power_series (x:: ComplexF32 ) = ComplexF32 (airybi_power_series (ComplexF64 (x), tol= eps (Float32)))
296
302
297
303
# ####
298
304
# #### Power series for airybiprime(x)
299
305
# ####
300
306
301
- function airybiprime_power_series (x:: ComplexOrReal{T} ) where T
307
+ function airybiprime_power_series (x:: ComplexOrReal{T} ; tol = eps (T) ) where T
302
308
S = eltype (x)
303
309
iszero (x) && return S (0.4482883573538264 )
304
310
MaxIter = 3000
@@ -312,12 +318,14 @@ function airybiprime_power_series(x::ComplexOrReal{T}) where T
312
318
for i in 0 : MaxIter
313
319
ai1 += t
314
320
ai2 += t2
315
- abs (t) < eps (T) * abs (ai1) && break
321
+ abs (t) < tol * abs (ai1) && break
316
322
t *= x3 * inv (9 * (i + one (T))* (i + T (1 )/ 3 ))
317
323
t2 *= x3 * inv (9 * (i + one (T))* (i + T (5 )/ 3 ))
318
324
end
319
325
return (ai1* 3 ^ (T (1 )/ 6 ) + ai2* 3 ^ (- T (7 )/ 6 ))
320
326
end
327
+ airybiprime_power_series (x:: Float32 ) = Float32 (airybiprime_power_series (Float64 (x), tol= eps (Float32)))
328
+ airybiprime_power_series (x:: ComplexF32 ) = ComplexF32 (airybiprime_power_series (ComplexF64 (x), tol= eps (Float32)))
321
329
322
330
# ####
323
331
# #### Large argument expansion for airy functions
@@ -422,7 +430,7 @@ function airybiprime_large_argument(z::Complex{T}) where T
422
430
end
423
431
424
432
# see equations 24 and relations using eq 25 and 26 in [1]
425
- function airy_large_arg_a (x:: ComplexOrReal{T} ) where T
433
+ function airy_large_arg_a (x:: ComplexOrReal{T} ; tol = eps (T) * 40 ) where T
426
434
S = eltype (x)
427
435
MaxIter = 3000
428
436
xsqr = sqrt (x)
@@ -432,13 +440,13 @@ function airy_large_arg_a(x::ComplexOrReal{T}) where T
432
440
a = 4 * xsqr* x
433
441
for i in 0 : MaxIter
434
442
out += t
435
- abs (t) < eps (T) * 50 * abs (out) && break
443
+ abs (t) < tol * abs (out) && break
436
444
t *= - 3 * (i + one (T)/ 6 ) * (i + T (5 )/ 6 ) / (a* (i + one (T)))
437
445
end
438
- return out * exp (- a / 6 ) / (pi ^ ( 3 / 2 ) * sqrt (xsqr))
446
+ return out * exp (- a / 6 ) / (π ^ ( T ( 3 ) / 2 ) * sqrt (xsqr))
439
447
end
440
448
441
- function airy_large_arg_b (x:: ComplexOrReal{T} ) where T
449
+ function airy_large_arg_b (x:: ComplexOrReal{T} ; tol = eps (T) * 40 ) where T
442
450
S = eltype (x)
443
451
MaxIter = 3000
444
452
xsqr = sqrt (x)
@@ -448,13 +456,13 @@ function airy_large_arg_b(x::ComplexOrReal{T}) where T
448
456
a = 4 * xsqr* x
449
457
for i in 0 : MaxIter
450
458
out += t
451
- abs (t) < eps (T) * 50 * abs (out) && break
459
+ abs (t) < tol * abs (out) && break
452
460
t *= 3 * (i + one (T)/ 6 ) * (i + T (5 )/ 6 ) / (a* (i + one (T)))
453
461
end
454
- return out * exp (a / 6 ) / (pi ^ ( 3 / 2 ) * sqrt (xsqr))
462
+ return out * exp (a / 6 ) / (π ^ ( T ( 3 ) / 2 ) * sqrt (xsqr))
455
463
end
456
464
457
- function airy_large_arg_c (x:: ComplexOrReal{T} ) where T
465
+ function airy_large_arg_c (x:: ComplexOrReal{T} ; tol = eps (T) * 40 ) where T
458
466
S = eltype (x)
459
467
MaxIter = 3000
460
468
xsqr = sqrt (x)
@@ -466,13 +474,13 @@ function airy_large_arg_c(x::ComplexOrReal{T}) where T
466
474
a = 4 * xsqr* x
467
475
for i in 0 : MaxIter
468
476
out += t
469
- abs (t) < eps (T) * 50 * abs (out) && break
477
+ abs (t) < tol * abs (out) && break
470
478
t *= - 3 * (i - one (T)/ 6 ) * (i + T (7 )/ 6 ) / (a* (i + one (T)))
471
479
end
472
- return out * exp (- a / 6 ) * sqrt (xsqr) / pi ^ ( 3 / 2 )
480
+ return out * exp (- a / 6 ) * sqrt (xsqr) / π ^ ( T ( 3 ) / 2 )
473
481
end
474
482
475
- function airy_large_arg_d (x:: ComplexOrReal{T} ) where T
483
+ function airy_large_arg_d (x:: ComplexOrReal{T} ; tol = eps (T) * 40 ) where T
476
484
S = eltype (x)
477
485
MaxIter = 3000
478
486
xsqr = sqrt (x)
@@ -484,12 +492,25 @@ function airy_large_arg_d(x::ComplexOrReal{T}) where T
484
492
a = 4 * xsqr* x
485
493
for i in 0 : MaxIter
486
494
out += t
487
- abs (t) < eps (T) * 50 * abs (out) && break
495
+ abs (t) < tol * abs (out) && break
488
496
t *= 3 * (i - one (T)/ 6 ) * (i + T (7 )/ 6 ) / (a* (i + one (T)))
489
497
end
490
- return - out * exp (a / 6 ) * sqrt (xsqr) / pi ^ ( 3 / 2 )
498
+ return - out * exp (a / 6 ) * sqrt (xsqr) / π ^ ( T ( 3 ) / 2 )
491
499
end
492
500
501
+ # negative arguments of airy functions oscillate around zero so as x -> -Inf it is more prone to cancellation
502
+ # to give best accuracy it is best to promote to Float64 numbers until the Float32 tolerance
503
+ airy_large_arg_a (x:: Float32 ) = (airy_large_arg_a (Float64 (x), tol= eps (Float32)))
504
+ airy_large_arg_a (x:: ComplexF32 ) = (airy_large_arg_a (ComplexF64 (x), tol= eps (Float32)))
505
+
506
+ airy_large_arg_b (x:: Float32 ) = Float32 (airy_large_arg_b (Float64 (x), tol= eps (Float32)))
507
+ airy_large_arg_b (x:: ComplexF32 ) = ComplexF32 (airy_large_arg_b (ComplexF64 (x), tol= eps (Float32)))
508
+
509
+ airy_large_arg_c (x:: Float32 ) = Float32 (airy_large_arg_c (Float64 (x), tol= eps (Float32)))
510
+ airy_large_arg_c (x:: ComplexF32 ) = ComplexF32 (airy_large_arg_c (ComplexF64 (x), tol= eps (Float32)))
511
+
512
+ airy_large_arg_d (x:: Float32 ) = Float32 (airy_large_arg_d (Float64 (x), tol= eps (Float32)))
513
+ airy_large_arg_d (x:: ComplexF32 ) = ComplexF32 (airy_large_arg_d (ComplexF64 (x), tol= eps (Float32)))
493
514
# calculates besselk from the power series of besseli using the continued fraction and wronskian
494
515
# this shift the order higher first to avoid cancellation in the power series of besseli along the imaginary axis
495
516
# for real arguments this is not needed because besseli can be computed stably over the entire real axis
0 commit comments