Mathematics7 min readExamples run on PHP 8.5.10

log()

Learn how PHP 8.4 log() computes natural and arbitrary-base logarithms, what it returns for 0, negatives and bad bases, and which mistakes to avoid.

Signature

log(float $num, float $base = M_E): float

Purpose

log() answers the question: "to what power must the base be raised to get this number?" Called with one argument, it returns the natural logarithm, which uses Euler's number e (about 2.71828) as its base. Called with a second argument, it returns the logarithm of the first value in that base.

Logarithms are useful whenever growth is multiplicative. Typical uses are estimating how many periods compound growth needs, counting how many digits or bits a number needs, and compressing values that span many orders of magnitude.

Signature

Parameters and defaults

  • $num: the value to take the logarithm of. It is a float, so integers and numeric strings are converted under the normal PHP typing rules.
  • $base: the optional base. It defaults to M_E, the constant for e, which is why log($x) is the natural logarithm.

Return value and failure cases

The function always returns a float: the logarithm of $num in the given base, or the natural logarithm if no base is passed.

Not every input has a real logarithm, so some results are special float values rather than errors:

  • log(0) returns -INF.
  • A negative $num returns NAN.
  • A base of exactly 1 returns NAN, because no power of 1 reaches any other number.

A base that is zero or negative is rejected with a ValueError. A non-numeric string passed to either parameter raises a TypeError.

Example 1: natural and explicit bases

The results are formatted with number_format() so the output does not depend on tiny floating-point differences.

Example
<?php
echo number_format(log(M_E), 4), "\n";
echo number_format(log(1), 4), "\n";
echo number_format(log(8, 2), 4), "\n";
echo number_format(log(1000, 10), 4), "\n";
Output
1.0000
0.0000
3.0000
3.0000

The logarithm of e is 1 and the logarithm of 1 is always 0 in any valid base. Eight is 2 to the third power, and 1000 is 10 to the third power.

Example 2: how many periods does growth take?

If a quantity grows by a fixed rate each period, the number of periods needed to multiply it by a factor is log(factor) / log(1 + rate). Rounding up gives whole periods.

Example
<?php
function periodsToMultiply(float $factor, float $rate): int
{
    return (int) ceil(log($factor) / log(1 + $rate));
}

echo json_encode([
    periodsToMultiply(2, 0.05),
    periodsToMultiply(3, 0.05),
    periodsToMultiply(10, 0.07),
]);
Output
[15,23,35]

The ratio of two natural logarithms equals the logarithm in any base, so this is the same as log($factor, 1 + $rate).

Example 3: edge cases

Example
<?php
var_dump(log(0));
var_dump(log(-1));
var_dump(log(10, 1));

try {
    log(10, 0);
} catch (ValueError $e) {
    echo $e->getMessage(), "\n";
}
Output
float(-INF)
float(NAN)
float(NAN)
log(): Argument #2 ($base) must be greater than 0

Zero and negative inputs produce special float values, while an impossible base of zero throws an exception you can catch.

Edge cases to remember

  • NAN and INF cannot be encoded by json_encode(). Check with is_nan() or is_finite() before encoding.
  • NAN is never equal to anything, including itself, so $result === NAN is always false.
  • Results are floating-point approximations. log(1000, 10) is intended to be 3, but comparing a computed logarithm with == is fragile in general. Round or use a tolerance.
  • Rounding up a ratio of logarithms can be off by one if the true answer is an exact integer and the float result lands slightly above it. Test boundary values when exactness matters.

Common mistakes

  1. Expecting base 10. In some other languages and calculators, log means base 10. In PHP it is natural. Use log10() or pass 10 as the base when you want common logarithms.
  2. Swapping the arguments. The value comes first and the base second. log(2, 8) is about 0.333, not 3.
  3. Confusing it with error_log(). Despite the name, error_log() sends messages to a log destination and has nothing to do with mathematics.
  4. Skipping input validation. Passing user data that may be zero or negative yields -INF or NAN, which then spreads through later calculations.
  5. Printing raw floats. Full float precision may show digits you did not expect. Use round() or number_format() for display.
  • log10(): base-10 logarithm.
  • exp(): the inverse of the natural logarithm, e raised to a power.
  • pow(): general exponentiation; pow($base, log($x, $base)) recovers approximately $x.
  • error_log(): unrelated logging function with a similar name.

Recap

log($num) is the natural logarithm and log($num, $base) uses your own base. It returns a float, gives -INF for 0 and NAN for negative numbers or a base of 1, and throws ValueError for a base that is zero or negative. Watch for float precision and remember that the default base is e, not 10.

Tested examples

Natural and explicit bases
<?php
echo number_format(log(M_E), 4), "\n";
echo number_format(log(1), 4), "\n";
echo number_format(log(8, 2), 4), "\n";
echo number_format(log(1000, 10), 4), "\n";
Output
1.0000
0.0000
3.0000
3.0000
Periods needed for compound growth
<?php
function periodsToMultiply(float $factor, float $rate): int
{
    return (int) ceil(log($factor) / log(1 + $rate));
}

echo json_encode([
    periodsToMultiply(2, 0.05),
    periodsToMultiply(3, 0.05),
    periodsToMultiply(10, 0.07),
]);
Output
[15,23,35]
Edge cases and invalid base
<?php
var_dump(log(0));
var_dump(log(-1));
var_dump(log(10, 1));

try {
    log(10, 0);
} catch (ValueError $e) {
    echo $e->getMessage(), "\n";
}
Output
float(-INF)
float(NAN)
float(NAN)
log(): Argument #2 ($base) must be greater than 0