Mathematics7 min readExamples run on PHP 8.5.10

expm1()

Learn how PHP 8.4 expm1() computes exp($num) - 1 accurately for values near zero, with examples, edge cases and common mistakes.

Signature

expm1(float $num): float
Available since PHP 4.1.07.48.08.18.28.38.48.5All versions →

Purpose

expm1() returns e raised to the power of a number, minus one. Mathematically that is the same as exp($num) - 1. The difference is in how the computation is done. When $num is very close to zero, exp($num) is almost exactly 1. Subtracting 1 from it then cancels nearly all the significant digits, and what is left is mostly rounding noise. expm1() is designed to avoid that loss, so the result stays accurate for tiny inputs.

The name reads as "exp minus 1". You will see it in numerical code that deals with small rates, small probabilities and growth factors, where the quantity you care about is the change from 1 rather than the value itself.

Signature

Parameters and defaults

  • $num: the exponent. It is required and has no default value.

Because the parameter is typed float, an integer argument is converted to a float. In the default (non-strict) mode a numeric string such as "0.5" is accepted too. A non-numeric string raises a TypeError, and so does an array. Under declare(strict_types=1) only int and float values are accepted.

Return value and failure cases

The function always returns a float: e to the power of $num, minus one. It does not return false and does not emit warnings for ordinary numbers. The edge cases come from floating-point limits:

  • expm1(0) is zero.
  • For very negative inputs the result approaches -1, and for sufficiently negative values it is -1 as a float.
  • For large positive inputs the true result exceeds what a float can hold, so you get INF.
  • NAN as input gives NAN.

Example 1: basic values and limits

The first example prints the classic e - 1, zero, a very negative input and an overflowing input. Output is formatted with printf() so it does not depend on float display details.

Example
<?php
printf("%.6f\n", expm1(1));
printf("%.1f\n", expm1(0));
var_dump(expm1(-1000));
var_dump(is_infinite(expm1(1000)));
Output
1.718282
0.0
float(-1)
bool(true)

Example 2: why not exp($x) - 1?

For $x = 1e-10, the exact answer is very close to 1.00000000005e-10. The naive subtraction has an absolute error of several times 1e-18, which is huge compared with the answer itself. The expm1() result is accurate to far better than that.

Example
<?php
$x = 1e-10;
$expected = 1.00000000005e-10;

$accurate = expm1($x);
$naive = exp($x) - 1;

var_dump(abs($accurate - $expected) < 1e-20);
var_dump(abs($naive - $expected) > 1e-20);
Output
bool(true)
bool(true)

The comparison uses a tolerance because floats should never be compared with == after calculation. Here the tolerance is much smaller than the error of the naive version, which is what makes the contrast visible.

Example 3: effective rate from a continuous rate

With continuous compounding at rate r, the growth factor over one period is exp(r). The gain is exp(r) - 1, which is exactly what expm1() computes.

Example
<?php
$rate = 0.05;
$balance = 1000;

printf("Effective annual rate: %.4f%%\n", expm1($rate) * 100);
printf("Interest on 1000: %.2f\n", $balance * expm1($rate));
Output
Effective annual rate: 5.1271%
Interest on 1000: 51.27

The interest comes straight from the gain, so there is no need to compute the full future balance and subtract the starting amount.

Edge cases

  • Tiny inputs. For very small $num, the result is approximately $num itself, because e^x - 1 is about x near zero. expm1() keeps the extra digits beyond that approximation.
  • Large inputs. Overflow produces INF. Check with is_infinite() if your inputs can be large.
  • Negative inputs. The result lies between -1 and 0. It never goes below -1, because exp() is always positive.
  • Integers. expm1(1) works the same as expm1(1.0). The return value is always a float, so do not expect an int.
  • Mid-range inputs. For values far from zero, exp($x) - 1 and expm1($x) agree closely, and the accuracy advantage disappears.

Common mistakes

  1. Forgetting that the result is already minus one. Writing expm1($x) - 1 subtracts twice. Use expm1($x) + 1 if you need the plain exponential back, although exp($x) is the better choice then.
  2. Using it for ordinary growth factors. If you need the full factor, exp() is clearer. expm1() is for the change from one.
  3. Comparing floats with ==. Results are approximations. Compare with a tolerance, or format with printf() or round() for display.
  4. Passing non-numeric strings. Input from users should be validated first, otherwise a TypeError can occur.
  5. Ignoring overflow. A large exponent silently becomes INF, which can then spread through later calculations.
  6. Mixing it up with log1p(). The two are inverse partners: log1p() is accurate for log(1 + x) near zero, while expm1() is accurate for exp(x) - 1 near zero.
  • exp() returns e to the power of a number, without subtracting one.
  • log1p() returns log(1 + number) with the same near-zero accuracy goal.
  • log() computes natural or custom-base logarithms.
  • pow() raises any base to a power.

Recap

expm1($num) gives exp($num) - 1 as a float, with accuracy preserved when $num is close to zero. Use it when the interesting quantity is a small change from one, such as a rate of gain. Remember that very large inputs overflow to INF, very negative inputs approach -1, and results should be compared with tolerances rather than strict equality.

Tested examples

Basic values and limits
<?php
printf("%.6f\n", expm1(1));
printf("%.1f\n", expm1(0));
var_dump(expm1(-1000));
var_dump(is_infinite(expm1(1000)));
Output
1.718282
0.0
float(-1)
bool(true)
Accuracy near zero compared with exp() - 1
<?php
$x = 1e-10;
$expected = 1.00000000005e-10;

$accurate = expm1($x);
$naive = exp($x) - 1;

var_dump(abs($accurate - $expected) < 1e-20);
var_dump(abs($naive - $expected) > 1e-20);
Output
bool(true)
bool(true)
Effective rate from a continuous rate
<?php
$rate = 0.05;
$balance = 1000;

printf("Effective annual rate: %.4f%%\n", expm1($rate) * 100);
printf("Interest on 1000: %.2f\n", $balance * expm1($rate));
Output
Effective annual rate: 5.1271%
Interest on 1000: 51.27