lg1 <- function(u) lgamma(u+1) # the simple direct form
## The curve, zeros at u=0 & u=1:
curve(lg1, -.2, 1.25, col=2, lwd=2, n=999)
title("lgamma(x + 1)"); abline(h=0, v=0:1, lty=3)
u <- (-16:100)/80 ; set.seed(1); u <- sample(u) # permuted (to check logic)
g11 <- vapply(u, gamln1, numeric(1))
gamln1. <- gamln1(u)
stopifnot( identical(g11, gamln1.) )
stopifnot( all.equal(lg1(u), g11) )
u <- (-160:1000)/800
relE <- sfsmisc::relErrV(gamln1(u), lg1(u))
plot(u, relE, type="l", main = expression("rel.diff." ~~ gamln1(u) %~~% lgamma(u+1)))
plot(u, abs(relE), type="l", log="y", yaxt="n",
main = expression("|rel.diff.|" ~~ gamln1(u) %~~% lgamma(u+1)))
sfsmisc::eaxis(2)
if(requireNamespace("DPQmpfr")) withAutoprint({
## Comparison using Rmpfr; extending the [-.2, 1.25] interval a bit
u <- seq(-0.225, 1.31, length.out = 2000)
lg1pM <- DPQmpfr::lgamma1pM(Rmpfr::mpfr(u, 128))
relE <- Rmpfr::asNumeric(sfsmisc::relErrV(lg1pM, gamln1(u, warnIf=FALSE)))
plot(relE ~ u, type="l", ylim = c(-1,1) * 2.3e-15,
main = expression("relative error of " ~~ gamln1(u) == log( Gamma(u+1) )))
grid(lty = 3); abline(v = c(-.2, 1.25), col = adjustcolor(4, 1/2), lty=2, lwd=2)
## well... TOMS 708 gamln1() is good (if "only" 14 digits required
## what about the direct formula -- how bad is it really ?
relED <- Rmpfr::asNumeric(sfsmisc::relErrV(lg1pM, lg1(u)))
lines(relED ~ u, col = adjustcolor(2, 1/2))
## amazingly, the direct formula is partly (around -0.2 and +0.4) even better than gamln1() !
plot(abs(relE) ~ u, type="l", log = "y", ylim = c(7e-17, 1e-14),
main = expression("|relative error| of " ~~ gamln1(u) == log( Gamma(u+1) )))
grid(lty = 3); abline(v = c(-.2, 1.25), col = adjustcolor(4, 1/2), lty=2, lwd=2)
relED <- Rmpfr::asNumeric(sfsmisc::relErrV(lg1pM, lg1(u)))
lines(abs(relED) ~ u, col = adjustcolor(2, 1/2))
})
Run the code above in your browser using DataLab