Skip to content

Commit 472eab6

Browse files
committed
move gamma and add tests
1 parent ef50a45 commit 472eab6

File tree

6 files changed

+72
-70
lines changed

6 files changed

+72
-70
lines changed

src/Bessels.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ include("recurrence.jl")
4040
include("misc.jl")
4141
include("Polynomials/besselj_polys.jl")
4242
include("asymptotics.jl")
43+
include("gamma.jl")
44+
4345
#include("hankel.jl")
4446

4547
end

src/besselj.jl

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -236,71 +236,3 @@ function log_besselj_small_arguments_orders(v, x::T) where T
236236
logout = -loggamma(v + 1) + fma(v, log(x/2), log(out))
237237
return exp(logout)
238238
end
239-
240-
# For 0.0 <= x < 171.5
241-
# Mean ULP = 0.55
242-
# Max ULP = 2.4
243-
# Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
244-
function gamma(x)
245-
if x < 0
246-
isinteger(x) && throw(DomainError(x, "NaN result for non-NaN input."))
247-
xp1 = abs(x) + 1.0
248-
return π / sinpi(xp1) / _gamma(xp1)
249-
else
250-
return _gamma(x)
251-
end
252-
end
253-
function _gamma(x)
254-
if x > 11.5
255-
return large_gamma(x)
256-
elseif x <= 11.5
257-
return small_gamma(x)
258-
elseif isnan(x)
259-
return x
260-
end
261-
end
262-
function large_gamma(x)
263-
isinf(x) && return x
264-
T = Float64
265-
w = inv(x)
266-
s = (
267-
8.333333333333331800504e-2, 3.472222222230075327854e-3, -2.681327161876304418288e-3, -2.294719747873185405699e-4,
268-
7.840334842744753003862e-4, 6.989332260623193171870e-5, -5.950237554056330156018e-4, -2.363848809501759061727e-5,
269-
7.147391378143610789273e-4
270-
)
271-
w = w * evalpoly(w, s) + one(T)
272-
# lose precision on following block
273-
y = exp((x))
274-
# avoid overflow
275-
v = x^(0.5 * x - 0.25)
276-
y = v * (v / y)
277-
278-
return SQ2PI(T) * y * w
279-
end
280-
function small_gamma(x)
281-
T = Float64
282-
P = (
283-
1.000000000000000000009e0, 8.378004301573126728826e-1, 3.629515436640239168939e-1, 1.113062816019361559013e-1,
284-
2.385363243461108252554e-2, 4.092666828394035500949e-3, 4.542931960608009155600e-4, 4.212760487471622013093e-5
285-
)
286-
Q = (
287-
9.999999999999999999908e-1, 4.150160950588455434583e-1, -2.243510905670329164562e-1, -4.633887671244534213831e-2,
288-
2.773706565840072979165e-2, -7.955933682494738320586e-4, -1.237799246653152231188e-3, 2.346584059160635244282e-4,
289-
-1.397148517476170440917e-5
290-
)
291-
292-
z = one(T)
293-
while x >= 3.0
294-
x -= one(T)
295-
z *= x
296-
end
297-
while x < 2.0
298-
z /= x
299-
x += one(T)
300-
end
301-
302-
x -= T(2)
303-
p = evalpoly(x, P)
304-
q = evalpoly(x, Q)
305-
return z * p / q
306-
end

src/gamma.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
2+
function gamma(x)
3+
if x < 0
4+
isinteger(x) && throw(DomainError(x, "NaN result for non-NaN input."))
5+
xp1 = abs(x) + 1.0
6+
return π / sinpi(xp1) / _gamma(xp1)
7+
else
8+
return _gamma(x)
9+
end
10+
end
11+
function _gamma(x)
12+
if x > 11.5
13+
return large_gamma(x)
14+
elseif x <= 11.5
15+
return small_gamma(x)
16+
elseif isnan(x)
17+
return x
18+
end
19+
end
20+
function large_gamma(x)
21+
isinf(x) && return x
22+
T = Float64
23+
w = inv(x)
24+
s = (
25+
8.333333333333331800504e-2, 3.472222222230075327854e-3, -2.681327161876304418288e-3, -2.294719747873185405699e-4,
26+
7.840334842744753003862e-4, 6.989332260623193171870e-5, -5.950237554056330156018e-4, -2.363848809501759061727e-5,
27+
7.147391378143610789273e-4
28+
)
29+
w = w * evalpoly(w, s) + one(T)
30+
# lose precision on following block
31+
y = exp((x))
32+
# avoid overflow
33+
v = x^(0.5 * x - 0.25)
34+
y = v * (v / y)
35+
36+
return SQ2PI(T) * y * w
37+
end
38+
function small_gamma(x)
39+
T = Float64
40+
P = (
41+
1.000000000000000000009e0, 8.378004301573126728826e-1, 3.629515436640239168939e-1, 1.113062816019361559013e-1,
42+
2.385363243461108252554e-2, 4.092666828394035500949e-3, 4.542931960608009155600e-4, 4.212760487471622013093e-5
43+
)
44+
Q = (
45+
9.999999999999999999908e-1, 4.150160950588455434583e-1, -2.243510905670329164562e-1, -4.633887671244534213831e-2,
46+
2.773706565840072979165e-2, -7.955933682494738320586e-4, -1.237799246653152231188e-3, 2.346584059160635244282e-4,
47+
-1.397148517476170440917e-5
48+
)
49+
50+
z = one(T)
51+
while x >= 3.0
52+
x -= one(T)
53+
z *= x
54+
end
55+
while x < 2.0
56+
z /= x
57+
x += one(T)
58+
end
59+
60+
x -= T(2)
61+
p = evalpoly(x, P)
62+
q = evalpoly(x, Q)
63+
return z * p / q
64+
end

test/bessely_test.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ y1_32 = bessely1.(Float32.(x))
6868
## Tests for bessely
6969

7070
## test all numbers and orders for 0<nu<100
71-
x = [0.05, 0.1, 0.2, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9, 0.92, 0.95, 0.97, 0.99, 1.0, 1.01, 1.05, 1.1, 1.2, 1.4, 2.0]
72-
nu = [2, 4, 6, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100]
71+
x = [0.05, 0.1, 0.2, 0.4, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.91, 0.92, 0.93, 0.95, 0.96, 0.97, 0.98, 0.99, 0.995, 0.999, 1.0, 1.001, 1.01, 1.05, 1.1, 1.2, 1.4, 1.6, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0, 10.0]
72+
nu = [2, 4, 6, 10, 15, 20, 25, 30, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 110, 125, 150, 175, 200]
7373
for v in nu, xx in x
7474
xx *= v
7575
sf = SpecialFunctions.bessely(BigFloat(v), BigFloat(xx))

test/gamma_test.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
x = rand(10000)*170
2+
@test SpecialFunctions.gamma.(BigFloat.(x)) Bessels.gamma.(x)
3+
@test SpecialFunctions.gamma.(BigFloat.(-x)) Bessels.gamma.(-x)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ import SpecialFunctions
66
@time @testset "besselk" begin include("besselk_test.jl") end
77
@time @testset "besselj" begin include("besselj_test.jl") end
88
@time @testset "bessely" begin include("bessely_test.jl") end
9+
@time @testset "gamma" begin include("gamma_test.jl") end

0 commit comments

Comments
 (0)