log1pmx | R Documentation |
log(1+x) - x
ComputationCompute
\log(1+x) - x
accurately also for small x
, i.e., |x| \ll 1
.
Since April 2021, the pure R code version log1pmx()
also works
for "mpfr" numbers (from package Rmpfr).
rlog1(x)
, provided mostly for reference and reproducibility, is
used in TOMS Algorithm 708, see e.g. the reference of lgamma1p
.
and computes minus log1pmx(x), i.e., x - \log(1+x)
,
using (argument reduction) and a rational approximation when
x \in [-0.39, 0.57)
.
log1pmx (x, tol_logcf = 1e-14, eps2 = 0.01, minL1 = -0.79149064,
trace.lcf = FALSE,
logCF = if(is.numeric(x)) logcf else logcfR.)
log1pmxC(x) # TODO in future: arguments (minL1, eps2, tol_logcf),
# possibly with *different* defaults (!)
rlog1(x)
x |
numeric (or, for |
tol_logcf |
a non-negative number indicating the tolerance
(maximal relative error) for the auxiliary |
eps2 |
non-negative cutoff where the algorithm switches from a few
terms, to using |
minL1 |
negative cutoff, called |
trace.lcf |
|
logCF |
the |
In order to provide full (double precision) accuracy,
the computations happens differently in three regions for x
,
m_l = \code{minL1} = -0.79149064
is the first cutpoint,
x < m_l
or x > 1
:use log1pmx(x) := log1p(x) - x
,
|x| < \epsilon_2
:use
t((((2/9 * y + 2/7)y + 2/5)y + 2/3)y - x)
,
x \in [ml,1]
, and |x| \ge \epsilon_2
:use
t(2y logcf(y, 3, 2) - x)
,
where t := \frac{x}{2 + x}
, and y := t^2
.
Note that the formulas based on t
are based on the (fast
converging) formula
\log(1+x) = 2\left(r + \frac{r^3}{3}+ \frac{r^5}{5} + \ldots\right),
where r := x/(x+2)
, see the reference.
log1pmxC()
is an interface to R C API (‘Rmathlib’) function.
a numeric vector (with the same attributes as x
).
A translation of Morten Welinder's C code of Jan 2005, see R's bug issue \Sexpr[results=rd]{tools:::Rd_expr_PR(7307)}, parametrized and tuned by Martin Maechler.
Abramowitz, M. and Stegun, I. A. (1972)
Handbook of Mathematical Functions. New York: Dover.
https://en.wikipedia.org/wiki/Abramowitz_and_Stegun provides
links to the full text which is in public domain.
Formula (4.1.29), p.68.
Martin Mächler (2021). log1pmx, ... Computing ... Probabilities in R. (DPQ package vignette)
logcf
, the auxiliary function,
lgamma1p
which calls log1pmx
, log1p
; also
expm1x)()
which computes expm1(x) - x
accurately, whereas
log1pmx(x)
computes log1p(x) - x
accurately
(doExtras <- DPQ:::doExtras()) # TRUE e.g. if interactive()
n1 <- if(doExtras) 1001 else 201
curve(log1pmx, -.9999, 7, n=n1); abline(h=0, v=-1:0, lty=3)
curve(log1pmx, -.1, .1, n=n1); abline(h=0, v=0, lty=3)
curve(log1pmx, -.01, .01, n=n1) -> l1xz2; abline(h=0, v=0, lty=3)
## C and R versions correspond closely:
with(l1xz2, stopifnot(all.equal(y, log1pmxC(x), tol = 1e-15)))
e <- if(doExtras) 2^-12 else 2^-8; by.p <- 1/(if(doExtras) 256 else 64)
xd <- c(seq(-1+e, 0+100*e, by=e), seq(by.p, 5, by=by.p)) # length 676 or 5476 if do.X.
plot(xd, log1pmx(xd), type="l", col=2, main = "log1pmx(x)")
abline(h=0, v=-1:0, lty=3)
## --- Compare rexp1() with log1pmx() ----------------------------
x <- seq(-0.5, 5/8, by=1/256)
all.equal(log1pmx(x), -rlog1(x), tol = 0) # 2.838e-16 {|rel.error| <= 1.33e-15}
stopifnot(all.equal(log1pmx(x), -rlog1(x), tol = 1e-14))
## much more closely:
x <- c(-1+1e-9, -1+1/256, -(127:50)/128, (-199:295)/512, 74:196/128)
if(is.unsorted(x)) stop("x must be sorted for plots")
rlog1.x <- rlog1(x)
summary(relD <- sfsmisc::relErrV(log1pmx(x), -rlog1.x))
n.relD <- relD * 2^53
table(n.relD)
## 64-bit Linux F36 (gcc 12.2.1):
## -6 -5 -4 -3 -2 -1 0 2 4 6 8 10 12 14
## 2 3 13 24 79 93 259 120 48 22 14 15 5 1
stopifnot(-10 <= n.relD, n.relD <= 20) # above Lnx: [-6, 14]
if(requireNamespace("Rmpfr")) {
relE <- Rmpfr::asNumeric(sfsmisc::relErrV(log1pmx(Rmpfr::mpfr(x,128)), -rlog1(x)))
plot(x, pmax(2^-54, abs(relE)), log="y", type="l", main= "|rel.Err| of rlog1(x)")
rl1.c <- c(-.39, 0.57, -.18, .18) # the cutoffs used inside rlog1()
lc <- "gray"
abline(v = rl1.c, col=lc, lty=2)
axis(3, at=rl1.c, col=lc, cex.axis=3/4, mgp=c(2,.5,0))
abline(h= (1:4)*2^-53, lty=3, col = (cg <- adjustcolor(1, 1/4)))
axis(4, at=(1:4)*2^-53, labels=expression(frac(epsilon[c],2), epsilon[c],
frac(3,2)*epsilon[c], 2*epsilon[c]),
cex.axis = 3/4, tcl=-1/4, las = 1, mgp=c(1.5,.5,0), col=cg)
## it seems the -.18 +.18 cutoffs should be slightly moved "outside"
}
## much more graphics etc in ../tests/dnbinom-tst.R (and the vignette, see above)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.