158 lines
6.9 KiB
Julia
158 lines
6.9 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
gamma(x::Float64) = nan_dom_err(ccall((:tgamma,libm), Float64, (Float64,), x), x)
|
||
gamma(x::Float32) = nan_dom_err(ccall((:tgammaf,libm), Float32, (Float32,), x), x)
|
||
|
||
"""
|
||
gamma(x)
|
||
|
||
Compute the gamma function of `x`.
|
||
"""
|
||
gamma(x::Real) = gamma(float(x))
|
||
|
||
function lgamma_r(x::Float64)
|
||
signp = Ref{Int32}()
|
||
y = ccall((:lgamma_r,libm), Float64, (Float64, Ptr{Int32}), x, signp)
|
||
return y, signp[]
|
||
end
|
||
function lgamma_r(x::Float32)
|
||
signp = Ref{Int32}()
|
||
y = ccall((:lgammaf_r,libm), Float32, (Float32, Ptr{Int32}), x, signp)
|
||
return y, signp[]
|
||
end
|
||
lgamma_r(x::Real) = lgamma_r(float(x))
|
||
lgamma_r(x::Number) = lgamma(x), 1 # lgamma does not take abs for non-real x
|
||
"`lgamma_r(x)`: return L,s such that `gamma(x) = s * exp(L)`" lgamma_r
|
||
|
||
"""
|
||
lfact(x)
|
||
|
||
Compute the logarithmic factorial of a nonnegative integer `x`.
|
||
Equivalent to [`lgamma`](@ref) of `x + 1`, but `lgamma` extends this function
|
||
to non-integer `x`.
|
||
"""
|
||
lfact(x::Integer) = x < 0 ? throw(DomainError()) : lgamma(x + oneunit(x))
|
||
|
||
"""
|
||
lgamma(x)
|
||
|
||
Compute the logarithm of the absolute value of [`gamma`](@ref) for
|
||
[`Real`](@ref) `x`, while for [`Complex`](@ref) `x` compute the
|
||
principal branch cut of the logarithm of `gamma(x)` (defined for negative `real(x)`
|
||
by analytic continuation from positive `real(x)`).
|
||
"""
|
||
function lgamma end
|
||
|
||
# asymptotic series for log(gamma(z)), valid for sufficiently large real(z) or |imag(z)|
|
||
@inline function lgamma_asymptotic(z::Complex{Float64})
|
||
zinv = inv(z)
|
||
t = zinv*zinv
|
||
# coefficients are bernoulli[2:n+1] .// (2*(1:n).*(2*(1:n) - 1))
|
||
return (z-0.5)*log(z) - z + 9.1893853320467274178032927e-01 + # <-- log(2pi)/2
|
||
zinv*@evalpoly(t, 8.3333333333333333333333368e-02,-2.7777777777777777777777776e-03,
|
||
7.9365079365079365079365075e-04,-5.9523809523809523809523806e-04,
|
||
8.4175084175084175084175104e-04,-1.9175269175269175269175262e-03,
|
||
6.4102564102564102564102561e-03,-2.9550653594771241830065352e-02)
|
||
end
|
||
|
||
# Compute the logΓ(z) function using a combination of the asymptotic series,
|
||
# the Taylor series around z=1 and z=2, the reflection formula, and the shift formula.
|
||
# Many details of these techniques are discussed in D. E. G. Hare,
|
||
# "Computing the principal branch of log-Gamma," J. Algorithms 25, pp. 221-236 (1997),
|
||
# and similar techniques are used (in a somewhat different way) by the
|
||
# SciPy loggamma function. The key identities are also described
|
||
# at http://functions.wolfram.com/GammaBetaErf/LogGamma/
|
||
function lgamma(z::Complex{Float64})
|
||
x = real(z)
|
||
y = imag(z)
|
||
yabs = abs(y)
|
||
if !isfinite(x) || !isfinite(y) # Inf or NaN
|
||
if isinf(x) && isfinite(y)
|
||
return Complex(x, x > 0 ? (y == 0 ? y : copysign(Inf, y)) : copysign(Inf, -y))
|
||
elseif isfinite(x) && isinf(y)
|
||
return Complex(-Inf, y)
|
||
else
|
||
return Complex(NaN, NaN)
|
||
end
|
||
elseif x > 7 || yabs > 7 # use the Stirling asymptotic series for sufficiently large x or |y|
|
||
return lgamma_asymptotic(z)
|
||
elseif x < 0.1 # use reflection formula to transform to x > 0
|
||
if x == 0 && y == 0 # return Inf with the correct imaginary part for z == 0
|
||
return Complex(Inf, signbit(x) ? copysign(oftype(x, pi), -y) : -y)
|
||
end
|
||
# the 2pi * floor(...) stuff is to choose the correct branch cut for log(sinpi(z))
|
||
return Complex(1.1447298858494001741434262, # log(pi)
|
||
copysign(6.2831853071795864769252842, y) # 2pi
|
||
* floor(0.5*x+0.25)) -
|
||
log(sinpi(z)) - lgamma(1-z)
|
||
elseif abs(x - 1) + yabs < 0.1
|
||
# taylor series around zero at z=1
|
||
# ... coefficients are [-eulergamma; [(-1)^k * zeta(k)/k for k in 2:15]]
|
||
w = Complex(x - 1, y)
|
||
return w * @evalpoly(w, -5.7721566490153286060651188e-01,8.2246703342411321823620794e-01,
|
||
-4.0068563438653142846657956e-01,2.705808084277845478790009e-01,
|
||
-2.0738555102867398526627303e-01,1.6955717699740818995241986e-01,
|
||
-1.4404989676884611811997107e-01,1.2550966952474304242233559e-01,
|
||
-1.1133426586956469049087244e-01,1.000994575127818085337147e-01,
|
||
-9.0954017145829042232609344e-02,8.3353840546109004024886499e-02,
|
||
-7.6932516411352191472827157e-02,7.1432946295361336059232779e-02,
|
||
-6.6668705882420468032903454e-02)
|
||
elseif abs(x - 2) + yabs < 0.1
|
||
# taylor series around zero at z=2
|
||
# ... coefficients are [1-eulergamma; [(-1)^k * (zeta(k)-1)/k for k in 2:12]]
|
||
w = Complex(x - 2, y)
|
||
return w * @evalpoly(w, 4.2278433509846713939348812e-01,3.2246703342411321823620794e-01,
|
||
-6.7352301053198095133246196e-02,2.0580808427784547879000897e-02,
|
||
-7.3855510286739852662729527e-03,2.8905103307415232857531201e-03,
|
||
-1.1927539117032609771139825e-03,5.0966952474304242233558822e-04,
|
||
-2.2315475845357937976132853e-04,9.9457512781808533714662972e-05,
|
||
-4.4926236738133141700224489e-05,2.0507212775670691553131246e-05)
|
||
end
|
||
# use recurrence relation lgamma(z) = lgamma(z+1) - log(z) to shift to x > 7 for asymptotic series
|
||
shiftprod = Complex(x,yabs)
|
||
x += 1
|
||
sb = false # == signbit(imag(shiftprod)) == signbit(yabs)
|
||
# To use log(product of shifts) rather than sum(logs of shifts),
|
||
# we need to keep track of the number of + to - sign flips in
|
||
# imag(shiftprod), as described in Hare (1997), proposition 2.2.
|
||
signflips = 0
|
||
while x <= 7
|
||
shiftprod *= Complex(x,yabs)
|
||
sb′ = signbit(imag(shiftprod))
|
||
signflips += sb′ & (sb′ != sb)
|
||
sb = sb′
|
||
x += 1
|
||
end
|
||
shift = log(shiftprod)
|
||
if signbit(y) # if y is negative, conjugate the shift
|
||
shift = Complex(real(shift), signflips*-6.2831853071795864769252842 - imag(shift))
|
||
else
|
||
shift = Complex(real(shift), imag(shift) + signflips*6.2831853071795864769252842)
|
||
end
|
||
return lgamma_asymptotic(Complex(x,y)) - shift
|
||
end
|
||
lgamma(z::Complex{T}) where {T<:Union{Integer,Rational}} = lgamma(float(z))
|
||
lgamma(z::Complex{T}) where {T<:Union{Float32,Float16}} = Complex{T}(lgamma(Complex{Float64}(z)))
|
||
|
||
gamma(z::Complex) = exp(lgamma(z))
|
||
|
||
"""
|
||
beta(x, y)
|
||
|
||
Euler integral of the first kind ``\\operatorname{B}(x,y) = \\Gamma(x)\\Gamma(y)/\\Gamma(x+y)``.
|
||
"""
|
||
function beta(x::Number, w::Number)
|
||
yx, sx = lgamma_r(x)
|
||
yw, sw = lgamma_r(w)
|
||
yxw, sxw = lgamma_r(x+w)
|
||
return exp(yx + yw - yxw) * (sx*sw*sxw)
|
||
end
|
||
|
||
"""
|
||
lbeta(x, y)
|
||
|
||
Natural logarithm of the absolute value of the [`beta`](@ref)
|
||
function ``\\log(|\\operatorname{B}(x,y)|)``.
|
||
"""
|
||
lbeta(x::Number, w::Number) = lgamma(x)+lgamma(w)-lgamma(x+w)
|