expm1

Returns exp(x) - 1 computed accurately even when x is very close to zero.

Signature
expm1(float $num): float
  • Added in PHP 4.1.0

Parameters

ParameterTypeDescription
$numfloatThe argument to process, used as the exponent.

Return value

floate raised to the power of $num, minus one, without the precision loss that exp($num) - 1 suffers near zero.

Errors

Throws a TypeError if $num is not a float or a value that can be coerced to float.

expm1() computes exp($num) - 1 as a single operation. Mathematically the two are identical; numerically they are not, and that difference is the entire reason the function exists.

Why it exists

When $num is small, exp($num) is a number just above 1. A 64-bit float has about 16 significant digits, so exp(1e-10) stores roughly 1.0000000001 and the digits describing the interesting part — the tiny excess over 1 — are the last few it can hold. Subtracting 1 discards all the leading digits and leaves whatever noise survived rounding. This is catastrophic cancellation. At 1e-16 the answer collapses to exactly 0.0. expm1() computes the small quantity directly and keeps full precision.

When to reach for it

Any time you write exp($x) - 1 and $x can be small. Typical cases: converting a small continuously compounded rate into a periodic rate, computing a percentage change from a log return, survival and hazard functions in statistics, and physics formulas where an exponent approaches zero.

For large $num the two forms agree to the last bit, so there is no reason to switch back — just use expm1() whenever the expression has that shape. Its counterpart for logarithms is log1p(), which computes log(1 + $x) with the same protection.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Convert a small continuously compounded interest rate into an effective periodic rate.
  • Turn a log return back into a percentage change without losing precision on small moves.
  • Evaluate survival or hazard functions in statistics where the exponent approaches zero.

Frequently asked questions

What is the difference between expm1 and exp?

expm1($x) returns exp($x) - 1 as one operation, avoiding the precision loss that happens when you subtract 1 from a number just above 1. For arguments far from zero the two give identical results.

When should I use expm1 instead of exp($x) - 1?

Whenever the argument can be small — small interest rates, log returns, near-zero exponents in statistics. Below about 1e-16 the naive form returns exactly 0.0 while expm1() stays accurate.

What is the logarithm equivalent of expm1?

log1p(), which computes log(1 + $x) accurately for small $x. expm1() and log1p() are exact inverses of each other and are normally used as a pair.

More examples

Where the two forms diverge

At 1e-2 the two agree to every digit shown. By 1e-10 the relative error of exp()-1 is around 1e-7, and at 1e-17 exp()-1 returns 0 while expm1 still reports 1e-17 — a 100% error. The damage grows steadily as the argument shrinks.

Example · php
<?php
foreach ([1e-2, 1e-6, 1e-10, 1e-14, 1e-17] as $x) {
    $a = expm1($x);
    $b = exp($x) - 1;
    $rel = $a == 0.0 ? 0.0 : abs($b - $a) / abs($a);
    printf("x=%-7.0e expm1=%-14.6e exp-1=%-14.6e rel.err=%.2e\n", $x, $a, $b, $rel);
}

Continuous rate to effective periodic rate

On a small rate the two effective rates differ in the eleventh significant digit — 0.000000013698630231 against 0.000000013698630230 — a relative error of about 5e-11. Even against a 250 million balance both figures still print as 3.424658, so the discrepancy stays far below a cent here; the reason finance code reaches for expm1() is that the relative error keeps growing as the rate shrinks, until at rates below about 1e-16 the naive form collapses to exactly zero.

Example · php
<?php
$annual = 0.000005;            // 0.0005% continuously compounded
$daily  = $annual / 365;

printf("effective daily (expm1): %.18f\n", expm1($daily));
printf("effective daily (naive): %.18f\n", exp($daily) - 1);

$principal = 250_000_000.0;    // 250 million
printf("one day interest: %.6f vs %.6f\n",
    $principal * expm1($daily), $principal * (exp($daily) - 1));

Round-tripping with log1p

log1p() is the inverse of expm1(), and the pair round-trips exactly even at 1e-12. Doing the same with log(1 + (exp($r) - 1)) loses the value entirely at that scale, because both halves cancel independently.

Example · php
<?php
$rates = [0.05, 1e-6, 1e-12];
foreach ($rates as $r) {
    $back = log1p(expm1($r));
    printf("r=%-8.0e round-trip=%-12.6e exact=%s\n",
        $r, $back, var_export($back === $r, true));
}

Discussion

  • Be the first to comment on this lesson.