Skip to content

Commit f772ccf

Browse files
authored
Merge pull request #14 from heltonmc/J0_medium_args
besselj0 and friends for medium arguments
2 parents 1d41167 + 00fe767 commit f772ccf

File tree

5 files changed

+80
-35
lines changed

5 files changed

+80
-35
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ We compare the relative [speed](https://github.com/heltonmc/Bessels.jl/blob/mast
4545

4646
| function | `Float32` | `Float64`
4747
| ------------- | ------------- | ------------- |
48-
| besselj0 | 1.7x | 1.8x
49-
| besselj1 | 1.7x | 1.9x
50-
| bessely0 | 1.9x | 1.8x
51-
| bessely1 | 1.7x | 1.7x
48+
| besselj0 | 1.7x | 3.1x
49+
| besselj1 | 1.7x | 3.0x
50+
| bessely0 | 1.9x | 2.7x
51+
| bessely1 | 1.7x | 2.7x
5252
| besseli0 | 26x | 13.2x
5353
| besseli1 | 22x | 13.9x
5454
| besseli(20, x) | 5.4x | 2.1x |

src/Bessels.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ module Bessels
22

33
export besselj0
44
export besselj1
5-
export besselj
65

76
export bessely0
87
export bessely1

src/besselj.jl

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
# Polynomial coefficients are from [1] which is based on [2]
1111
# For tiny arugments the power series expansion is used.
1212
#
13-
# Branch 2: 5.0 < x < 75.0
13+
# Branch 2: 5.0 < x < 25.0
1414
# besselj0 = sqrt(2/(pi*x))*(cos(x - pi/4)*R7(x) - sin(x - pi/4)*R8(x))
1515
# Hankel's asymptotic expansion is used
1616
# where R7 and R8 are rational functions (Pn(x)/Qn(x)) of degree 7 and 8 respectively
1717
# See section 4 of [3] for more details and [1] for coefficients of polynomials
1818
#
19-
# Branch 3: x >= 75.0
19+
# Branch 3: x >= 25.0
2020
# besselj0 = sqrt(2/(pi*x))*beta(x)*(cos(x - pi/4 - alpha(x))
2121
# See modified expansions given in [3]. Exact coefficients are used
2222
#
@@ -28,7 +28,14 @@
2828
# [3] Harrison, John. "Fast and accurate Bessel function computation."
2929
# 2009 19th IEEE Symposium on Computer Arithmetic. IEEE, 2009.
3030
#
31-
function besselj0(x::T) where T
31+
32+
"""
33+
besselj0(x::T) where T <: Union{Float32, Float64}
34+
35+
Bessel function of the first kind of order zero, ``J_0(x)``.
36+
"""
37+
function besselj0(x::Float64)
38+
T = Float64
3239
x = abs(x)
3340
isinf(x) && return zero(x)
3441

@@ -42,7 +49,7 @@ function besselj0(x::T) where T
4249
p = (z - DR1) * (z - DR2)
4350
p = p * evalpoly(z, RP_j0(T)) / evalpoly(z, RQ_j0(T))
4451
return p
45-
elseif x < 75.0
52+
elseif x < 25.0
4653
w = 5.0 / x
4754
q = 25.0 / (x * x)
4855

@@ -53,14 +60,18 @@ function besselj0(x::T) where T
5360
p = p * sc[2] - w * q * sc[1]
5461
return p * SQ2OPI(T) / sqrt(x)
5562
else
63+
if x < 120.0
64+
p = (one(T), -1/16, 53/512, -4447/8192, 3066403/524288, -896631415/8388608, 796754802993/268435456, -500528959023471/4294967296)
65+
q = (-1/8, 25/384, -1073/5120, 375733/229376, -55384775/2359296, 24713030909/46137344, -7780757249041/436207616)
66+
else
67+
p = (one(T), -1/16, 53/512, -4447/8192)
68+
q = (-1/8, 25/384, -1073/5120, 375733/229376)
69+
end
5670
xinv = inv(x)
5771
x2 = xinv*xinv
5872

59-
p = (one(T), -1/16, 53/512, -4447/8192, 5066403/524288)
6073
p = evalpoly(x2, p)
6174
a = SQ2OPI(T) * sqrt(xinv) * p
62-
63-
q = (-1/8, 25/384, -1073/5120, 375733/229376, -55384775/2359296)
6475
xn = muladd(xinv, evalpoly(x2, q), - PIO4(T))
6576

6677
# the following computes b = cos(x + xn) more accurately
@@ -93,6 +104,11 @@ function besselj0(x::Float32)
93104
end
94105
end
95106

107+
"""
108+
besselj1(x::T) where T <: Union{Float32, Float64}
109+
110+
Bessel function of the first kind of order one, ``J_1(x)``.
111+
"""
96112
function besselj1(x::Float64)
97113
T = Float64
98114
x = abs(x)
@@ -103,7 +119,7 @@ function besselj1(x::Float64)
103119
w = evalpoly(z, RP_j1(T)) / evalpoly(z, RQ_j1(T))
104120
w = w * x * (z - 1.46819706421238932572e1) * (z - 4.92184563216946036703e1)
105121
return w
106-
elseif x < 75.0
122+
elseif x < 25.0
107123
w = 5.0 / x
108124
z = w * w
109125
p = evalpoly(z, PP_j1(T)) / evalpoly(z, PQ_j1(T))
@@ -113,14 +129,18 @@ function besselj1(x::Float64)
113129
p = p * sc[2] - w * q * sc[1]
114130
return p * SQ2OPI(T) / sqrt(x)
115131
else
132+
if x < 120.0
133+
p = (one(T), 3/16, -99/512, 6597/8192, -4057965/524288, 1113686901/8388608, -951148335159/268435456, 581513783771781/4294967296)
134+
q = (3/8, -21/128, 1899/5120, -543483/229376, 8027901/262144, -30413055339/46137344, 9228545313147/436207616)
135+
else
136+
p = (one(T), 3/16, -99/512, 6597/8192)
137+
q = (3/8, -21/128, 1899/5120, -543483/229376)
138+
end
116139
xinv = inv(x)
117140
x2 = xinv*xinv
118141

119-
p = (one(T), 3/16, -99/512, 6597/8192, -4057965/524288)
120142
p = evalpoly(x2, p)
121143
a = SQ2OPI(T) * sqrt(xinv) * p
122-
123-
q = (3/8, -21/128, 1899/5120, -543483/229376, 8027901/262144)
124144
xn = muladd(xinv, evalpoly(x2, q), - 3 * PIO4(T))
125145

126146
# the following computes b = cos(x + xn) more accurately
@@ -129,7 +149,6 @@ function besselj1(x::Float64)
129149
return a * b
130150
end
131151
end
132-
133152
function besselj1(x::Float32)
134153
x = abs(x)
135154
isinf(x) && return zero(x)

src/bessely.jl

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
# Polynomial coefficients are from [1] which is based on [2].
1111
# For tiny arugments the power series expansion is used.
1212
#
13-
# Branch 2: 5.0 < x < 75.0
13+
# Branch 2: 5.0 < x < 25.0
1414
# bessely0 = sqrt(2/(pi*x))*(sin(x - pi/4)*R7(x) - cos(x - pi/4)*R8(x))
1515
# Hankel's asymptotic expansion is used
1616
# where R7 and R8 are rational functions (Pn(x)/Qn(x)) of degree 7 and 8 respectively
1717
# See section 4 of [3] for more details and [1] for coefficients of polynomials
1818
#
19-
# Branch 3: x >= 75.0
19+
# Branch 3: x >= 25.0
2020
# bessely0 = sqrt(2/(pi*x))*beta(x)*(sin(x - pi/4 - alpha(x))
2121
# See modified expansions given in [3]. Exact coefficients are used.
2222
#
@@ -28,6 +28,12 @@
2828
# [3] Harrison, John. "Fast and accurate Bessel function computation."
2929
# 2009 19th IEEE Symposium on Computer Arithmetic. IEEE, 2009.
3030
#
31+
32+
"""
33+
bessely0(x::T) where T <: Union{Float32, Float64}
34+
35+
Bessel function of the second kind of order zero, ``Y_0(x)``.
36+
"""
3137
function bessely0(x::T) where T <: Union{Float32, Float64}
3238
if x <= zero(x)
3339
if iszero(x)
@@ -42,29 +48,33 @@ function bessely0(x::T) where T <: Union{Float32, Float64}
4248
end
4349
function _bessely0_compute(x::Float64)
4450
T = Float64
45-
if x <= 5
51+
if x <= 5.0
4652
z = x * x
4753
w = evalpoly(z, YP_y0(T)) / evalpoly(z, YQ_y0(T))
4854
w += TWOOPI(T) * log(x) * besselj0(x)
4955
return w
50-
elseif x < 75.0
51-
w = T(5) / x
52-
z = w*w
56+
elseif x < 25.0
57+
w = 5.0 / x
58+
z = w * w
5359
p = evalpoly(z, PP_y0(T)) / evalpoly(z, PQ_y0(T))
5460
q = evalpoly(z, QP_y0(T)) / evalpoly(z, QQ_y0(T))
5561
xn = x - PIO4(T)
5662
sc = sincos(xn)
5763
p = p * sc[1] + w * q * sc[2]
5864
return p * SQ2OPI(T) / sqrt(x)
5965
else
66+
if x < 120.0
67+
p = (one(T), -1/16, 53/512, -4447/8192, 3066403/524288, -896631415/8388608, 796754802993/268435456, -500528959023471/4294967296)
68+
q = (-1/8, 25/384, -1073/5120, 375733/229376, -55384775/2359296, 24713030909/46137344, -7780757249041/436207616)
69+
else
70+
p = (one(T), -1/16, 53/512, -4447/8192)
71+
q = (-1/8, 25/384, -1073/5120, 375733/229376)
72+
end
6073
xinv = inv(x)
6174
x2 = xinv*xinv
6275

63-
p = (one(T), -1/16, 53/512, -4447/8192, 5066403/524288)
6476
p = evalpoly(x2, p)
6577
a = SQ2OPI(T) * sqrt(xinv) * p
66-
67-
q = (-1/8, 25/384, -1073/5120, 375733/229376, -55384775/2359296)
6878
xn = muladd(xinv, evalpoly(x2, q), - PIO4(T))
6979

7080
# the following computes b = sin(x + xn) more accurately
@@ -91,6 +101,12 @@ function _bessely0_compute(x::Float32)
91101
return p
92102
end
93103
end
104+
105+
"""
106+
bessely1(x::T) where T <: Union{Float32, Float64}
107+
108+
Bessel function of the second kind of order one, ``Y_1(x)``.
109+
"""
94110
function bessely1(x::T) where T <: Union{Float32, Float64}
95111
if x <= zero(x)
96112
if iszero(x)
@@ -103,16 +119,15 @@ function bessely1(x::T) where T <: Union{Float32, Float64}
103119
end
104120
return _bessely1_compute(x)
105121
end
106-
107122
function _bessely1_compute(x::Float64)
108123
T = Float64
109124
if x <= 5
110125
z = x * x
111126
w = x * (evalpoly(z, YP_y1(T)) / evalpoly(z, YQ_y1(T)))
112127
w += TWOOPI(T) * (besselj1(x) * log(x) - inv(x))
113128
return w
114-
elseif x < 75.0
115-
w = T(5) / x
129+
elseif x < 25.0
130+
w = 5.0 / x
116131
z = w * w
117132
p = evalpoly(z, PP_j1(T)) / evalpoly(z, PQ_j1(T))
118133
q = evalpoly(z, QP_j1(T)) / evalpoly(z, QQ_j1(T))
@@ -121,14 +136,18 @@ function _bessely1_compute(x::Float64)
121136
p = p * sc[1] + w * q * sc[2]
122137
return p * SQ2OPI(T) / sqrt(x)
123138
else
139+
if x < 120.0
140+
p = (one(T), 3/16, -99/512, 6597/8192, -4057965/524288, 1113686901/8388608, -951148335159/268435456, 581513783771781/4294967296)
141+
q = (3/8, -21/128, 1899/5120, -543483/229376, 8027901/262144, -30413055339/46137344, 9228545313147/436207616)
142+
else
143+
p = (one(T), 3/16, -99/512, 6597/8192)
144+
q = (3/8, -21/128, 1899/5120, -543483/229376)
145+
end
124146
xinv = inv(x)
125147
x2 = xinv*xinv
126148

127-
p = (one(T), 3/16, -99/512, 6597/8192, -4057965/524288)
128149
p = evalpoly(x2, p)
129150
a = SQ2OPI(T) * sqrt(xinv) * p
130-
131-
q = (3/8, -21/128, 1899/5120, -543483/229376, 8027901/262144)
132151
xn = muladd(xinv, evalpoly(x2, q), - 3 * PIO4(T))
133152

134153
# the following computes b = sin(x + xn) more accurately
@@ -137,7 +156,6 @@ function _bessely1_compute(x::Float64)
137156
return a * b
138157
end
139158
end
140-
141159
function _bessely1_compute(x::Float32)
142160
T = Float32
143161
if x <= 2.0f0

src/misc.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# written by @oscardssmith
44
function cos_sum(x, xn)
55
s = x + xn
6-
n, r = Base.Math.rem_pio2_kernel(s)
6+
n, r = reduce_pi02_med(s)
77
lo = r.lo - ((s - x) - xn)
88
hi = r.hi + lo
99
y = Base.Math.DoubleFloat64(hi, r.hi-hi+lo)
@@ -21,7 +21,7 @@ end
2121
# function to more accurately compute sin(x + xn)
2222
function sin_sum(x, xn)
2323
s = x + xn
24-
n, r = Base.Math.rem_pio2_kernel(s)
24+
n, r = reduce_pi02_med(s)
2525
lo = r.lo - ((s - x) - xn)
2626
hi = r.hi + lo
2727
y = Base.Math.DoubleFloat64(hi, r.hi-hi+lo)
@@ -36,3 +36,12 @@ function sin_sum(x, xn)
3636
return -Base.Math.cos_kernel(y)
3737
end
3838
end
39+
@inline function reduce_pi02_med(x::Float64)
40+
pio2_1 = 1.57079632673412561417e+00
41+
42+
fn = round(x*(2/pi))
43+
r = muladd(-fn, pio2_1, x)
44+
w = fn * 6.07710050650619224932e-11
45+
y = r-w
46+
return unsafe_trunc(Int, fn), Base.Math.DoubleFloat64(y, (r-y)-w)
47+
end

0 commit comments

Comments
 (0)