log1p
Computes log(1 + x) accurately even when x is very close to zero.
log1p(float $num): float- Added in PHP 4.1.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$num | float | The value to add to 1 before taking the natural logarithm. |
Return value
floatlog(1 + num), computed in a way that stays accurate for values of num close to zero.
log1p($x) computes log(1 + $x) — but accurately for small $x. Note carefully what it takes: the x, not the 1 + x.
The problem it solves
A double has about 16 significant digits near 1.0. If $x is 1e-16 then 1 + $x rounds straight back to 1.0 before log() ever sees it, and you get 0.0 instead of roughly 1e-16. Even at 1e-9, where the addition survives, you have already discarded half of your significant digits. The error is invisible in a single call and catastrophic after a few million of them, which is exactly the situation where the number is small in the first place.
When to reach for it
Any time the argument to a logarithm is "1 plus something small": per-period interest and growth rates, continuously compounded returns, log-probabilities near certainty, relative error terms, and statistical likelihoods. Its inverse partner is expm1(), which computes exp($x) - 1 with the same trick; use them together so precision survives the round trip.
For arguments well away from zero log1p($x) and log(1 + $x) agree, so there is no cost to defaulting to log1p(). log1p(-1) is -INF, and anything below -1 returns NAN.
Example
When to use it
- Converting a tiny per-period interest or growth rate into a continuously compounded rate.
- Accumulating log-likelihoods where individual probabilities sit very close to 1.
- Computing log(1 + relative_error) in numerical analysis without losing digits.
- Handling per-second or per-millisecond rates that get raised to very large powers.
Frequently asked questions
When should I use log1p instead of log?
Whenever the argument would be 1 plus a small number. Below roughly 1e-8 the expression log(1 + $x) has already lost half its significant digits, while log1p($x) keeps all of them.
Does log1p take x or 1 + x?
It takes x. log1p(0.05) computes log(1.05). Passing log1p(1 + $x) computes log(2 + $x) instead, which is the classic bug with this function.
What is the inverse of log1p?
expm1(), which computes exp($x) - 1 accurately near zero. expm1(log1p($x)) round-trips small values that exp(log(1 + $x)) - 1 would destroy.
More examples
Comparing against the true value
The Taylor series x - x^2/2 + x^3/3 is the mathematically correct value for such a small argument. log1p() matches it to every printed digit; log(1 + r) diverges around the ninth significant figure, because the information was already lost in the addition before the logarithm was taken.
<?php
$r = 1.0e-10;
printf("log(1 + r) = %.18e\n", log(1 + $r));
printf("log1p(r) = %.18e\n", log1p($r));
printf("series = %.18e\n", $r - $r ** 2 / 2 + $r ** 3 / 3);Round-tripping with expm1()
log1p() and expm1() are designed as a pair, so taking the logarithm and undoing it returns the original value essentially intact. The naive route through log() and exp() loses several significant digits in each direction, and the subtraction of 1 at the end throws away most of what survived.
<?php
$small = 2.5e-12;
printf("original: %.18e\n", $small);
printf("log1p/expm1: %.18e\n", expm1(log1p($small)));
printf("log/exp: %.18e\n", exp(log(1 + $small)) - 1);
Discussion