|
| 1 | +# Airy functions |
| 2 | +# |
| 3 | +# airyai(x), airybi(nu, x) |
| 4 | +# airyaiprime(x), airybiprime(nu, x) |
| 5 | +# |
| 6 | +# A numerical routine to compute the airy functions and their derivatives. |
| 7 | +# These routines use their relations to other special functions using https://dlmf.nist.gov/9.6. |
| 8 | +# Specifically see (NIST 9.6.E1 - 9.6.E9) for computation from the defined bessel functions. |
| 9 | +# For negative arguments these definitions are prone to some cancellation leading to higher errors. |
| 10 | +# In the future, these could be replaced with more custom routines as they depend on a single variable. |
| 11 | +# |
| 12 | + |
1 | 13 | """
|
2 | 14 | airyai(x)
|
3 | 15 | Airy function of the first kind ``\\operatorname{Ai}(x)``.
|
4 | 16 | """
|
5 |
| -function airyai(x::T) where T |
| 17 | +airyai(x::Real) = _airyai(float(x)) |
| 18 | + |
| 19 | +_airyai(x::Float16) = Float16(_airyai(Float32(x))) |
| 20 | + |
| 21 | +function _airyai(x::T) where T <: Union{Float32, Float64} |
| 22 | + isnan(x) && return x |
| 23 | + x_abs = abs(x) |
| 24 | + z = 2 * x_abs^(T(3)/2) / 3 |
| 25 | + |
6 | 26 | if x > zero(T)
|
7 |
| - z = 2 * x^(T(3)/2) / 3 |
8 | 27 | return sqrt(x / 3) * besselk(one(T)/3, z) / π
|
9 | 28 | elseif x < zero(T)
|
10 |
| - x_abs = abs(x) |
11 |
| - z = 2 * x_abs^(T(3)/2) / 3 |
12 | 29 | Jv, Yv = besseljy_positive_args(one(T)/3, z)
|
13 | 30 | Jmv = (Jv - sqrt(T(3)) * Yv) / 2
|
14 |
| - return sqrt(x_abs) * (Jmv + Jv) / 3 |
| 31 | + return isinf(z) ? throw(DomainError(x, "airyai(x) is not defined.")) : sqrt(x_abs) * (Jmv + Jv) / 3 |
15 | 32 | elseif iszero(x)
|
16 | 33 | return T(0.3550280538878172)
|
17 | 34 | end
|
|
21 | 38 | airyaiprime(x)
|
22 | 39 | Derivative of the Airy function of the first kind ``\\operatorname{Ai}'(x)``.
|
23 | 40 | """
|
24 |
| -function airyaiprime(x::T) where T |
| 41 | +airyaiprime(x::Real) = _airyaiprime(float(x)) |
| 42 | + |
| 43 | +_airyaiprime(x::Float16) = Float16(_airyaiprime(Float32(x))) |
| 44 | + |
| 45 | +function _airyaiprime(x::T) where T <: Union{Float32, Float64} |
| 46 | + isnan(x) && return x |
| 47 | + x_abs = abs(x) |
| 48 | + z = 2 * x_abs^(T(3)/2) / 3 |
| 49 | + |
25 | 50 | if x > zero(T)
|
26 |
| - z = 2 * x^(T(3)/2) / 3 |
27 | 51 | return -x * besselk(T(2)/3, z) / (sqrt(T(3)) * π)
|
28 | 52 | elseif x < zero(T)
|
29 |
| - x_abs = abs(x) |
30 |
| - z = 2 * x_abs^(T(3)/2) / 3 |
31 | 53 | Jv, Yv = besseljy_positive_args(T(2)/3, z)
|
32 | 54 | Jmv = -(Jv + sqrt(T(3))*Yv) / 2
|
33 |
| - return x_abs * (Jv - Jmv) / 3 |
| 55 | + return isinf(z) ? throw(DomainError(x, "airyaiprime(x) is not defined.")) : x_abs * (Jv - Jmv) / 3 |
34 | 56 | elseif iszero(x)
|
35 | 57 | return T(-0.2588194037928068)
|
36 | 58 | end
|
|
40 | 62 | airybi(x)
|
41 | 63 | Airy function of the second kind ``\\operatorname{Bi}(x)``.
|
42 | 64 | """
|
43 |
| -function airybi(x::T) where T |
| 65 | +airybi(x::Real) = _airybi(float(x)) |
| 66 | + |
| 67 | +_airybi(x::Float16) = Float16(_airybi(Float32(x))) |
| 68 | + |
| 69 | +function _airybi(x::T) where T <: Union{Float32, Float64} |
| 70 | + isnan(x) && return x |
| 71 | + x_abs = abs(x) |
| 72 | + z = 2 * x_abs^(T(3)/2) / 3 |
| 73 | + |
44 | 74 | if x > zero(T)
|
45 |
| - z = 2 * x^(T(3)/2) / 3 |
46 | 75 | return sqrt(x / 3) * (besseli(-one(T)/3, z) + besseli(one(T)/3, z))
|
47 | 76 | elseif x < zero(T)
|
48 |
| - x_abs = abs(x) |
49 |
| - z = 2 * x_abs^(T(3)/2) / 3 |
50 | 77 | Jv, Yv = besseljy_positive_args(one(T)/3, z)
|
51 | 78 | Jmv = (Jv - sqrt(T(3)) * Yv) / 2
|
52 |
| - return sqrt(x_abs/3) * (Jmv - Jv) |
| 79 | + return isinf(z) ? throw(DomainError(x, "airybi(x) is not defined.")) : sqrt(x_abs/3) * (Jmv - Jv) |
53 | 80 | elseif iszero(x)
|
54 | 81 | return T(0.6149266274460007)
|
55 | 82 | end
|
|
60 | 87 | Derivative of the Airy function of the second kind ``\\operatorname{Bi}'(x)``.
|
61 | 88 | """
|
62 | 89 | function airybiprime(x::T) where T
|
| 90 | + isnan(x) && return x |
| 91 | + x_abs = abs(x) |
| 92 | + z = 2 * x_abs^(T(3)/2) / 3 |
| 93 | + |
63 | 94 | if x > zero(T)
|
64 |
| - z = 2 * x^(T(3)/2) / 3 |
65 | 95 | return x * (besseli(T(2)/3, z) + besseli(-T(2)/3, z)) / sqrt(T(3))
|
66 | 96 | elseif x < zero(T)
|
67 |
| - x_abs = abs(x) |
68 |
| - z = 2 * x_abs^(T(3)/2) / 3 |
69 | 97 | Jv, Yv = besseljy_positive_args(T(2)/3, z)
|
70 | 98 | Jmv = -(Jv + sqrt(T(3))*Yv) / 2
|
71 |
| - return x_abs * (Jv + Jmv) / sqrt(T(3)) |
| 99 | + return isinf(z) ? throw(DomainError(x, "airybiprime(x) is not defined.")) : x_abs * (Jv + Jmv) / sqrt(T(3)) |
72 | 100 | elseif iszero(x)
|
73 | 101 | return T(0.4482883573538264)
|
74 | 102 | end
|
|
0 commit comments