Math.log()

ES1+

Returns the natural logarithm (base e) of a number, the inverse of Math.exp(). Inputs must be positive: Math.log(0) is -Infinity, negative inputs return NaN, and Math.log(1) is exactly 0. For other bases, JavaScript provides Math.log10 and Math.log2, or the change-of-base formula.

Syntax

Math.log(x)

Parameters

x number

A number

Return Value

number

The natural logarithm of the given number

Examples

JavaScript
console.log(Math.log(1));
console.log(Math.log(Math.E));
console.log(Math.log(10));
Output:
// 0 1 2.302585092994046

📌 When to Use

Use Math.log() wherever quantities grow multiplicatively and you need them additive or linear: converting exponential growth to straight lines for charting and regression, computing how many periods compound growth needs to reach a target (t = Math.log(target / principal) / Math.log(1 + rate)), information-theoretic measures (entropy, log-likelihoods, where summing logs replaces multiplying tiny probabilities that would underflow to 0), perceptual scales (decibels, as in the example; pitch; brightness), log-scaled sliders that make "1 to 1,000,000" feel navigable, and algorithm analysis. Choose the right base deliberately: natural log for calculus-flavored math and rates, Math.log2 for bits, tree depths, and "how many doublings", Math.log10 for orders of magnitude and human-readable scales; the dedicated functions are clearer and more accurate than dividing by Math.LN10 or Math.LN2. Respect the domain edges as data-validation concerns: zero produces -Infinity and negatives produce NaN, both of which flow silently through downstream math, so real datasets (which contain zeros) need either filtering, a small floor, or the log1p transform. For values very close to 1, Math.log1p(x) computes log(1 + x) without the catastrophic precision loss of adding first, essential for small rates and probabilities.

⚠️ Common Mistakes

Assuming base 10: in JavaScript (as in most programming languages) Math.log is the natural log, so Math.log(100) is 4.605..., not 2. Spreadsheet and school notation habits die hard; Math.log10(100) is the base-10 function, and misreading this inflates or deflates every derived figure by a factor of ln(10).

Feeding zeros and negatives: Math.log(0) is -Infinity and Math.log(-5) is NaN, neither throws, and both propagate through sums and means invisibly. Datasets with zero counts (empty categories, silent audio frames) must be handled explicitly before log-scaling.

Losing precision near 1: Math.log(1 + 1e-12) evaluates the addition first, and 1 + 1e-12 has already lost most of the tiny value's digits; Math.log1p(1e-12) preserves them. Interest rates, small probabilities, and relative changes live exactly in this danger zone.

Sloppy change-of-base: Math.log(1000) / Math.log(10) gives 2.9999999999999996, so Math.floor of it gives 2 instead of 3, the classic digit-count bug. Use Math.log10 directly, or round intelligently when the result should be an integer.

Log-scaling axes that include zero or negatives by silently dropping points: charts that filter without disclosure mislead; the honest options are symlog-style transforms, a documented floor (Math.log(Math.max(x, minPositive))), or cube-root scaling for signed data.

Exponentiating carelessly on the way back: recovering values with Math.exp after summing many logs can overflow to Infinity or underflow to 0; numerical code uses the log-sum-exp trick (subtract the max before exponentiating) to stay in range.

✅ Best Practices

Pick the semantic base: Math.log2(n) for tree depth and bit width (Math.ceil(Math.log2(states)) bits), Math.log10(n) for magnitude displays, Math.log for math where e is natural; reserve change-of-base division for genuinely exotic bases, with rounding guards.

Use Math.log1p and its inverse Math.expm1 for anything of the form log(1 + small) or exp(small) - 1: continuously compounded rates, per-period growth conversions, and probability increments retain full precision this way.

Sum logs instead of multiplying many small numbers: log-domain accumulation (total += Math.log(p)) avoids underflow in likelihoods and long product chains, converting back only at the end (with log-sum-exp when needed).

For log-scaled UI (sliders, axes), map in both directions through one utility pair, toLog and fromLog, with the domain floor decision encoded once; symmetric, tested mapping prevents the drift between slider position and displayed value.

Guard domains at the edge: const safeLog = (x) => x > 0 ? Math.log(x) : fallback, choosing the fallback (skip, floor, error) as an explicit product decision rather than letting -Infinity choose for you.

⚡ Performance Notes

Math.log() is a transcendental call in the same cost band as sin and cos, tens of nanoseconds: irrelevant for UI math, sliders, and chart transforms over thousands of points, and only worth attention in per-sample audio processing or million-row analytics loops. Cache repeated constants, if you divide by Math.log(10) or Math.log(base) in a loop, hoist the denominator (or use Math.log10/Math.log2, which are also more accurate), and precompute log-transformed columns once when charts re-render with different visual settings but identical data. Math.log1p costs about the same as Math.log, so precision there is free. In genuinely hot numerical kernels, batch transforms into typed arrays and consider WebAssembly; and remember the spec does not require correctly rounded results, so cross-engine last-bit differences make exact-equality tests on logged values unreliable.

🌍 Real World Example

Decibel Sound Level Calculator

Decibels exist because human hearing is logarithmic: equal loudness steps are equal ratios of intensity, not equal differences. This example converts an intensity ratio to dB with 10 * Math.log10(I / I0), classifies the result against familiar reference levels, and shows the guard required for zero or negative input readings. The same logarithmic transform powers VU meters in audio software, Richter-style magnitude scales, pH displays, and the log-scaled axes that make an epidemic curve or a compound-growth chart readable.

function calculateDecibels(intensity, referenceIntensity = 1e-12) {
  if (intensity <= 0) {
    return { error: 'Intensity must be positive' };
  }

  // dB = 10 * log10(I / I0) = 10 * ln(I/I0) / ln(10)
  const decibels = 10 * Math.log(intensity / referenceIntensity) / Math.log(10);

  // Or use Math.log10 directly
  const decibelsAlt = 10 * Math.log10(intensity / referenceIntensity);

  return {
    decibels: decibels.toFixed(1),
    description: getDecibelDescription(decibels)
  };
}

function getDecibelDescription(db) {
  if (db < 30) return 'Very quiet (whisper)';
  if (db < 60) return 'Normal conversation';
  if (db < 90) return 'Loud (traffic)';
  return 'Very loud (potential hearing damage)';
}

console.log(calculateDecibels(1e-6));
// { decibels: '60.0', description: 'Normal conversation' }