Skip to content

Commit 23ec9f1

Browse files
Sumegh-gitsimonbyrne
authored andcommitted
Rename lgamma/lbeta to log(abs)gamma/log(abs)beta (#156)
See behaviour of `logdet`/`logabsdet` in the LinearAlgebra stdlib
1 parent d3c0e60 commit 23ec9f1

File tree

5 files changed

+139
-103
lines changed

5 files changed

+139
-103
lines changed

docs/src/index.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ libraries.
4646
| [`besselk(nu,z)`](@ref SpecialFunctions.besselk) | modified [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind of order `nu` at `z` |
4747
| [`besselkx(nu,z)`](@ref SpecialFunctions.besselkx) | scaled modified Bessel function of the second kind of order `nu` at `z` |
4848
| [`gamma(x)`](@ref SpecialFunctions.gamma) | [gamma function](https://en.wikipedia.org/wiki/Gamma_function) at `x` |
49+
| [`loggamma(x)`](@ref SpecialFunctions.loggamma) | accurate `log(gamma(x))` for large `x` |
50+
| [`logabsgamma(x)`](@ref SpecialFunctions.logabsgamma) | accurate `log(abs(gamma(x)))` for large `x` |
4951
| [`lgamma(x)`](@ref SpecialFunctions.lgamma) | accurate `log(gamma(x))` for large `x` |
5052
| [`lfactorial(x)`](@ref SpecialFunctions.lfactorial) | accurate `log(factorial(x))` for large `x`; same as `lgamma(x+1)` for `x > 1`, zero otherwise |
5153
| [`beta(x,y)`](@ref SpecialFunctions.beta) | [beta function](https://en.wikipedia.org/wiki/Beta_function) at `x,y` |
52-
| [`lbeta(x,y)`](@ref SpecialFunctions.lbeta) | accurate `log(beta(x,y))` for large `x` or `y` |
53-
54+
| [`logbeta(x,y)`](@ref SpecialFunctions.logbeta) | accurate `log(beta(x,y))` for large `x` or `y` |
55+
| [`logabsbeta(x,y)`](@ref SpecialFunctions.logabsbeta) | accurate `log(abs(beta(x,y)))` for large `x` or `y` |
5456
## Installation
5557

5658
The package is available for Julia versions 0.5 and up. To install it, run

docs/src/special.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ SpecialFunctions.ellipe
4949
SpecialFunctions.eta
5050
SpecialFunctions.zeta
5151
SpecialFunctions.gamma
52-
SpecialFunctions.lgamma
52+
SpecialFunctions.loggamma
53+
SpecialFunctions.logabsgamma
5354
SpecialFunctions.lfactorial
5455
SpecialFunctions.beta
55-
SpecialFunctions.lbeta
56+
SpecialFunctions.logbeta
57+
SpecialFunctions.logabsbeta
5658
```

src/deprecated.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
@deprecate airy(z::Number) airyai(z)
44
@deprecate airyx(z::Number) airyaix(z)
55
@deprecate airyprime(z::Number) airyaiprime(z)
6+
@deprecate lgamma(x::Real) logabsgamma(x)[1]
7+
@deprecate lgamma(x::Number) loggamma(x)
8+
@deprecate lgamma_r(x::Real) logabsgamma(x)
9+
@deprecate lgamma_r(x::Number) (loggamma(x), 1)
10+
@deprecate lbeta(x::Real, w::Real) logabsbeta(x, w)[1]
11+
@deprecate lbeta(x::Number, w::Number) logbeta(x, w)
612

713
function _airy(k::Integer, z::Complex{Float64})
814
Base.depwarn("`airy(k,x)` is deprecated, use `airyai(x)`, `airyaiprime(x)`, `airybi(x)` or `airybiprime(x)` instead.",:airy)

src/gamma.jl

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ function zeta(s::ComplexOrReal{Float64})
412412
end
413413
if absim > 12 # amplitude of sinpi(s/2) ≈ exp(imag(s)*π/2)
414414
# avoid overflow/underflow (issue #128)
415-
lg = lgamma(1 - s)
415+
lg = loggamma(1 - s)
416416
ln2pi = 1.83787706640934548356 # log(2pi) to double precision
417417
rehalf = real(s)*0.5
418418
return zeta(1 - s) * exp(lg + absim*(pi/2) + s*ln2pi) * (0.5/π) *
@@ -551,7 +551,7 @@ function polygamma(m::Integer, z::Number)
551551
polygamma(m, x)
552552
end
553553

554-
export gamma, lgamma, beta, lbeta, lfactorial
554+
export gamma, loggamma, logabsgamma, beta, logbeta, logabsbeta, lfactorial
555555

556556
## from base/special/gamma.jl
557557

@@ -567,47 +567,56 @@ Compute the gamma function of `x`.
567567
"""
568568
gamma(x::Real) = gamma(float(x))
569569

570-
function lgamma_r(x::Float64)
570+
function logabsgamma(x::Float64)
571571
signp = Ref{Int32}()
572572
y = ccall((:lgamma_r,libm), Float64, (Float64, Ptr{Int32}), x, signp)
573573
return y, signp[]
574574
end
575-
function lgamma_r(x::Float32)
575+
function logabsgamma(x::Float32)
576576
signp = Ref{Int32}()
577577
y = ccall((:lgammaf_r,libm), Float32, (Float32, Ptr{Int32}), x, signp)
578578
return y, signp[]
579579
end
580-
lgamma_r(x::Real) = lgamma_r(float(x))
581-
lgamma_r(x::Number) = lgamma(x), 1 # lgamma does not take abs for non-real x
582-
"""
583-
lgamma_r(x)
580+
logabsgamma(x::Real) = logabsgamma(float(x))
581+
logabsgamma(x::Float16) = Float16.(logabsgamma(Float32(x)))
582+
logabsgamma(x::Integer) = logabsgamma(float(x))
583+
logabsgamma(x::AbstractFloat) = throw(MethodError(logabsgamma, x))
584584

585-
Return L,s such that `gamma(x) = s * exp(L)`
586-
"""
587-
lgamma_r
588585

589586
"""
590587
lfactorial(x)
591588
592589
Compute the logarithmic factorial of a nonnegative integer `x`.
593-
Equivalent to [`lgamma`](@ref) of `x + 1`, but `lgamma` extends this function
590+
Equivalent to [`loggamma`](@ref) of `x + 1`, but `loggamma` extends this function
594591
to non-integer `x`.
595592
"""
596-
lfactorial(x::Integer) = x < 0 ? throw(DomainError(x, "`x` must be non-negative.")) : lgamma(x + oneunit(x))
593+
lfactorial(x::Integer) = x < 0 ? throw(DomainError(x, "`x` must be non-negative.")) : loggamma(x + oneunit(x))
597594
Base.@deprecate lfact lfactorial
598595

599596
"""
600-
lgamma(x)
597+
logabsgamma(x)
598+
599+
Compute the logarithm of absolute value of [`gamma`](@ref) for
600+
[`Real`](@ref) `x`and returns a tuple (logabsgamma(x), sign(gamma(x))).
601+
"""
602+
function logabsgamma end
603+
604+
"""
605+
loggamma(x)
601606
602-
Compute the logarithm of the absolute value of [`gamma`](@ref) for
603-
[`Real`](@ref) `x`, while for [`Complex`](@ref) `x` compute the
604-
principal branch cut of the logarithm of `gamma(x)` (defined for negative `real(x)`
605-
by analytic continuation from positive `real(x)`).
607+
Computes the logarithm of [`gamma`](@ref) for given `x`
606608
"""
607-
function lgamma end
609+
function loggamma end
610+
611+
function loggamma(x::Real)
612+
(y, s) = logabsgamma(x)
613+
s < 0.0 && throw(DomainError(x, "`gamma(x)` must be non-negative"))
614+
return y
615+
end
616+
loggamma(x::Number) = loggamma(float(x))
608617

609618
# asymptotic series for log(gamma(z)), valid for sufficiently large real(z) or |imag(z)|
610-
@inline function lgamma_asymptotic(z::Complex{Float64})
619+
function loggamma_asymptotic(z::Complex{Float64})
611620
zinv = inv(z)
612621
t = zinv*zinv
613622
# coefficients are bernoulli[2:n+1] .// (2*(1:n).*(2*(1:n) - 1))
@@ -625,7 +634,7 @@ end
625634
# and similar techniques are used (in a somewhat different way) by the
626635
# SciPy loggamma function. The key identities are also described
627636
# at http://functions.wolfram.com/GammaBetaErf/LogGamma/
628-
function lgamma(z::Complex{Float64})
637+
function loggamma(z::Complex{Float64})
629638
x = real(z)
630639
y = imag(z)
631640
yabs = abs(y)
@@ -638,7 +647,7 @@ function lgamma(z::Complex{Float64})
638647
return Complex(NaN, NaN)
639648
end
640649
elseif x > 7 || yabs > 7 # use the Stirling asymptotic series for sufficiently large x or |y|
641-
return lgamma_asymptotic(z)
650+
return loggamma_asymptotic(z)
642651
elseif x < 0.1 # use reflection formula to transform to x > 0
643652
if x == 0 && y == 0 # return Inf with the correct imaginary part for z == 0
644653
return Complex(Inf, signbit(x) ? copysign(oftype(x, pi), -y) : -y)
@@ -647,7 +656,7 @@ function lgamma(z::Complex{Float64})
647656
return Complex(1.1447298858494001741434262, # log(pi)
648657
copysign(6.2831853071795864769252842, y) # 2pi
649658
* floor(0.5*x+0.25)) -
650-
log(sinpi(z)) - lgamma(1-z)
659+
log(sinpi(z)) - loggamma(1-z)
651660
elseif abs(x - 1) + yabs < 0.1
652661
# taylor series around zero at z=1
653662
# ... coefficients are [-eulergamma; [(-1)^k * zeta(k)/k for k in 2:15]]
@@ -671,7 +680,7 @@ function lgamma(z::Complex{Float64})
671680
-2.2315475845357937976132853e-04,9.9457512781808533714662972e-05,
672681
-4.4926236738133141700224489e-05,2.0507212775670691553131246e-05)
673682
end
674-
# use recurrence relation lgamma(z) = lgamma(z+1) - log(z) to shift to x > 7 for asymptotic series
683+
# use recurrence relation loggamma(z) = loggamma(z+1) - log(z) to shift to x > 7 for asymptotic series
675684
shiftprod = Complex(x,yabs)
676685
x += 1
677686
sb = false # == signbit(imag(shiftprod)) == signbit(yabs)
@@ -692,33 +701,53 @@ function lgamma(z::Complex{Float64})
692701
else
693702
shift = Complex(real(shift), imag(shift) + signflips*6.2831853071795864769252842)
694703
end
695-
return lgamma_asymptotic(Complex(x,y)) - shift
704+
return loggamma_asymptotic(Complex(x,y)) - shift
696705
end
697-
lgamma(z::Complex{T}) where {T<:Union{Integer,Rational}} = lgamma(float(z))
698-
lgamma(z::Complex{T}) where {T<:Union{Float32,Float16}} = Complex{T}(lgamma(Complex{Float64}(z)))
706+
loggamma(z::Complex{T}) where {T<:Union{Integer,Rational}} = loggamma(float(z))
707+
loggamma(z::Complex{T}) where {T<:Union{Float32,Float16}} = Complex{T}(loggamma(Complex{Float64}(z)))
699708

700-
gamma(z::Complex) = exp(lgamma(z))
709+
gamma(z::Complex) = exp(loggamma(z))
701710

702711
"""
703712
beta(x, y)
704713
705714
Euler integral of the first kind ``\\operatorname{B}(x,y) = \\Gamma(x)\\Gamma(y)/\\Gamma(x+y)``.
706715
"""
707-
function beta(x::Number, w::Number)
708-
yx, sx = lgamma_r(x)
709-
yw, sw = lgamma_r(w)
710-
yxw, sxw = lgamma_r(x+w)
716+
function beta end
717+
718+
function beta(x::Real, w::Real)
719+
yx, sx = logabsgamma(x)
720+
yw, sw = logabsgamma(w)
721+
yxw, sxw = logabsgamma(x+w)
711722
return exp(yx + yw - yxw) * (sx*sw*sxw)
712723
end
713724

725+
function beta(x::Number, w::Number)
726+
yx = loggamma(x)
727+
yw = loggamma(w)
728+
yxw = loggamma(x+w)
729+
return exp(yx + yw - yxw)
730+
end
731+
714732
"""
715-
lbeta(x, y)
733+
logbeta(x, y)
716734
717-
Natural logarithm of the absolute value of the [`beta`](@ref)
735+
Natural logarithm of the [`beta`](@ref)
718736
function ``\\log(|\\operatorname{B}(x,y)|)``.
719737
"""
720-
lbeta(x::Number, w::Number) = lgamma(x)+lgamma(w)-lgamma(x+w)
738+
logbeta(x::Number, w::Number) = loggamma(x)+loggamma(w)-loggamma(x+w)
739+
740+
"""
741+
logabsbeta(x, y)
721742
743+
Returns a tuple of the natural logarithm of the absolute value of the [`beta`](@ref) function ``\\log(|\\operatorname{B}(x,y)|)`` and sign of the [`beta`](@ref) function .
744+
"""
745+
function logabsbeta(x::Real, w::Real)
746+
yx, sx = logabsgamma(x)
747+
yw, sw = logabsgamma(w)
748+
yxw, sxw = logabsgamma(x+w)
749+
(yx + yw - yxw), (sx*sw*sxw)
750+
end
722751
## from base/mpfr.jl
723752

724753
# Functions for which NaN results are converted to DomainError, following Base
@@ -731,15 +760,18 @@ function gamma(x::BigFloat)
731760
end
732761

733762
# log of absolute value of gamma function
734-
function lgamma_r(x::BigFloat)
763+
function logabsgamma(x::BigFloat)
735764
z = BigFloat()
736765
lgamma_signp = Ref{Cint}()
737766
ccall((:mpfr_lgamma,:libmpfr), Cint, (Ref{BigFloat}, Ref{Cint}, Ref{BigFloat}, Int32), z, lgamma_signp, x, ROUNDING_MODE[])
738767
return z, lgamma_signp[]
739768
end
740769

741-
lgamma(x::BigFloat) = lgamma_r(x)[1]
742-
770+
function loggamma(x::BigFloat)
771+
(y, s) = logabsgamma(x)
772+
s < 0.0 && throw(DomainError(x, "`gamma(x)` must be non-negative"))
773+
return y
774+
end
743775
if Base.MPFR.version() >= v"4.0.0"
744776
function beta(y::BigFloat, x::BigFloat)
745777
z = BigFloat()
@@ -760,12 +792,6 @@ end
760792

761793
## from base/math.jl
762794

763-
@inline lgamma(x::Float64) = nan_dom_err(ccall((:lgamma, libm), Float64, (Float64,), x), x)
764-
@inline lgamma(x::Float32) = nan_dom_err(ccall((:lgammaf, libm), Float32, (Float32,), x), x)
765-
@inline lgamma(x::Float16) = Float16(lgamma(Float32(x)))
766-
@inline lgamma(x::Real) = lgamma(float(x))
767-
lgamma(x::AbstractFloat) = throw(MethodError(lgamma, x))
768-
769795
## from base/numbers.jl
770796

771797
# this trickery is needed while the deprecated method in Base exists
@@ -793,6 +819,6 @@ function lbinomial(n::T, k::T) where {T<:Integer}
793819
if k > (n>>1)
794820
k = n - k
795821
end
796-
-log1p(n) - lbeta(n - k + one(T), k + one(T))
822+
-log1p(n) - logabsbeta(n - k + one(T), k + one(T))[1]
797823
end
798824
lbinomial(n::Integer, k::Integer) = lbinomial(promote(n, k)...)

0 commit comments

Comments
 (0)