2.2 Gamma Function
Gamma function: generalization of factorial function to the real or complex numbers. Factorial numbers are only defined with 0 or positive integers. Here we only handle real number Gamma function. For real work, use gamma R internal function. Many distribution and probability functions depend on gamma or log gamma function.
\[\Gamma (x) = \int_0^{\infty} t^{x-1}\mathrm{e}^{-t}\mathrm{d}t\]
while x is from 0 to infinity.
See Rudin’s book 3e p192 for more detail.
User defined GAMMA function using Lanczos approximation
GAMMA
## function (z)
## {
## if (is.nan(z))
## return(NaN)
## if (z == -Inf)
## return(NaN)
## if (z > 171.61)
## return(+Inf)
## if (z <= 0 & z == floor(z))
## return(NaN)
## if (z < 0.5)
## return(pi/(sin(pi * z) * GAMMA(1 - z)))
## if (z == floor(z) & z < 172)
## return(tableFactorial(z - 1))
## sqrt2pi = 2.506628274631
## p = c(676.520368121885, -1259.1392167224, 771.323428777653,
## -176.615029162141, 12.5073432786869, -0.13857109526572,
## 9.98436957801957e-06, 1.50563273514931e-07)
## z = z - 1
## x = 0.99999999999981
## for (i in 1:8) x = x + p[i]/(z + i)
## t = z + 7.5
## if (z > 141.2) {
## return(sqrt2pi * exp((z + 0.5) * log(t) - t + log(x)))
## }
## else {
## return(sqrt2pi * t^(z + 0.5) * exp(-t) * x)
## }
## }
## <bytecode: 0x000001e2a88f6540>
## <environment: namespace:math>
GAMMA(0)
## [1] NaN
GAMMA(1) # 0! = 1
## [1] 1
GAMMA(2) # 1! = 1
## [1] 1
GAMMA(171) # 170! = 7.257416e+306
## [1] 7.257e+306
format(GAMMA(0.5), digits=22) # = sqrt(pi) = 1.772453850905516
## [1] "1.772453850905516326009"
format(gamma(0.5), digits=22)
## [1] "1.772453850905516103964"
format(sqrt(pi), digits=22)
## [1] "1.772453850905515881919"
format(GAMMA(1.5), digits=22)
## [1] "0.8862269254527587181158"
format(gamma(1.5), digits=22)
## [1] "0.886226925452758051982"
For very large values (the result value exceeding .Machine$double.xmax), we need to use log gamma function.
LGAMMA
## function (z)
## {
## if (is.nan(z))
## return(NaN)
## if (z == -Inf)
## return(NaN)
## if (z > 2.53273727608008e+305)
## return(+Inf)
## if (z <= 0 & z == floor(z))
## return(NaN)
## if (z < 0.5)
## return(log(pi/sin(pi * z)) + LGAMMA(1 - z))
## if (abs(z) <= 171)
## return(log(abs(GAMMA(z))))
## else if (abs(z) > 1e+17)
## return(z * (log(z) - 1))
## else {
## lnsqrt2pi = 0.918938533204673
## p = c(676.520368121885, -1259.1392167224, 771.323428777653,
## -176.615029162141, 12.5073432786869, -0.13857109526572,
## 9.98436957801957e-06, 1.50563273514931e-07)
## z = z - 1
## x = 0.99999999999981
## for (i in 1:8) x = x + p[i]/(z + i)
## t = z + 7.5
## return(lnsqrt2pi + (z + 0.5) * log(t) - t + log(x))
## }
## }
## <bytecode: 0x000001e2a3ffc9f8>
## <environment: namespace:math>
LGAMMA(0)
## [1] NaN
LGAMMA(1) # log(0!) = 0
## [1] 0
LGAMMA(2) # log(1!) = 0
## [1] 0
LGAMMA(171) # log(170!) = 706.5731
## [1] 706.6
LGAMMA(-171) # NaN for all negative intergers
## [1] NaN
format(LGAMMA(0.5), digits=22) # = log(sqrt(pi)) = 0.5723649429247
## [1] "0.5723649429247003039833"
format(lgamma(0.5), digits=22)
## [1] "0.5723649429247000819387"
format(log(sqrt(pi)), digits=22)
## [1] "0.5723649429246999709164"
format(LGAMMA(1.5), digits=22)
## [1] "-0.1207822376352444271319"
format(lgamma(1.5), digits=22)
## [1] "-0.1207822376352451765325"
When you call factorial function in R, it calls gamma function.
Comparison of LGAMMA function and lgamma R internal funciton
= 3 # skip zero values
Start = 1000000
End = 1e-15 # relative tolerance
RelTol for (i in Start:End) {
= LGAMMA(i)
x1 = lgamma(i)
x2 = abs((x1 - x2)/x2)
RelDiff if (RelDiff > RelTol) print(paste(i, format(c(x1, x2), digits=22)))
}
= 1e-8 # absolute tolerance
AbsTol for (i in Start:End) {
<- LGAMMA(i)
x1 <- lgamma(i)
x2 if (abs(x1 - x2) > AbsTol) print(paste(i, format(c(x1, x2), digits=22)))
}
With above test, there should be no printout to be successful. If you make the tolerance more strict, you can see the differences.