Skip to content

Commit bb0b5c8

Browse files
authored
add Float32 gamma
From my testing this is roughly 3x faster than SpecialFunctions. It's 8.1ns for inputs <5 and 21.7ns for inputs greater than 5. Max error is .511 ulp.
1 parent d9f15ef commit bb0b5c8

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

src/gamma.jl

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Adapted from Cephes Mathematical Library (MIT license https://en.smath.com/view/CephesMathLibrary/license) by Stephen L. Moshier
2-
gamma(x::Float64) = _gamma(x)
3-
gamma(x::Float32) = Float32(_gamma(Float64(x)))
2+
gamma(x::Union{Float32, Float64}) = _gamma(x)
43

54
function _gamma(x::Float64)
65
T = Float64
@@ -50,6 +49,31 @@ function _gamma(x::Float64)
5049
return z * p / q
5150
end
5251

52+
function _gamma(_x::Float32)
53+
isfinite(_x) || return _x
54+
x = Float64(_x)
55+
if _x < 0
56+
s = sinpi(x)
57+
s == 0 && throw(DomainError(_x, "NaN result for non-NaN input."))
58+
x = 1 - x
59+
end
60+
if x < 5
61+
z = 1.
62+
while x>1
63+
x -= 1
64+
z *= x
65+
end
66+
num = evalpoly(x, (1.0, 0.41702538904450015, 0.24081703455575904, 0.04071509011391178, 0.015839573267537377))
67+
den = x*evalpoly(x, (1.0, 0.9942411061082665, -0.17434932941689474, -0.13577921102050783, 0.03028452206514555))
68+
res = z*num/den
69+
else
70+
x -= 1
71+
w = evalpoly(inv(x), (2.506628299028453, 0.20888413086840676, 0.008736513049552962, -0.007022997182153692, 0.0006787969600290756))
72+
res = @fastmath sqrt(x) * exp(log(x*1/ℯ) * x) * w
73+
end
74+
return Float32(_x<0 ? π / (s * res) : res)
75+
end
76+
5377
function gamma(n::Integer)
5478
n < 0 && throw(DomainError(n, "`n` must not be negative."))
5579
n == 0 && return Inf*one(n)

0 commit comments

Comments
 (0)