Math for AI course · Lesson 8 of 180
Logarithms for AI: Keep Tiny Probability Products from Vanishing
Learn logarithms as inverse powers, derive the product-to-sum laws, and use NumPy log scores to distinguish probability products that float64 rounds to zero.
A small language model assigns probability to each chosen token in a simplified sequence-scoring example. A sequence with 400 such choices has the mathematically nonzero product
Add one more equally likely token and the product is . Those are
different positive numbers, yet NumPy stores both products as 0.0 when it
calculates them with 64-bit floating-point numbers. A ranking based on the
stored products has lost the difference.
Logarithms preserve a more useful representation: the two products become the finite sums and . By the end of this lesson, you will be able to read a logarithm as an inverse power, derive the laws that turn products into sums, calculate a short sequence score by hand, and implement the same idea without pretending that log space removes every numerical limit.
This lesson reverses the exponent operation developed in Lesson 7: Powers for AI, whose canonical English route belongs to the course’s four-locale Translation Set. The official Mathematics for Machine Learning companion divides its path into mathematical foundations and the machine-learning problems that use them. Its introductory chapter motivates building foundations before relying on probabilistic models; the logarithm mathematics below is an original probability bridge rather than a definition attributed to Chapter 1.
The missing answer is an exponent
A logarithm asks one precise question: which exponent produces this positive number from the chosen base?
For example, because , while because . The negative answer is an exponent, not a negative input.
Three bases appear often in computing:
| Name | Notation used here | Base | One useful reading |
|---|---|---|---|
| Common logarithm | Decimal orders of magnitude | ||
| Natural logarithm | Probability and optimization formulas | ||
| Binary logarithm | Doublings and powers of two |
Some fields write log without a base, but that convention is not universal.
This lesson writes for the natural logarithm and includes a subscript for
other bases. NumPy follows the same practical choice:
numpy.log
computes the natural logarithm element by element.
The inverse relationship gives two checks whenever both expressions are in their real domains:
Multiplication leaves an additive trail
The product law is not a pattern to memorize in isolation. It falls directly out of the exponent law from Lesson 7.
Take positive numbers and , and use a valid logarithm base , . Let
The definition says and . Multiplying and applying the same-base exponent law gives
The exponent that produces is therefore :
Division subtracts exponents under the same assumptions:
Raising a positive number to a real power multiplies its exponent:
Positivity is doing real work in all three laws: and keep every real logarithm defined, and also keeps the quotient denominator nonzero.
Addition does not follow the product law. For a quick counterexample,
but
So in general. A stable operation for adding values that are already stored as logarithms appears later in this lesson, and it is deliberately different from product-to-sum conversion.
Four token choices, worked in both representations
Suppose two candidate continuations each contain four token choices. For this small calculation, treat each listed as the model’s positive conditional probability for the chosen token at position . Multiplying the four factors produces a sequence score; adding their natural logarithms produces the corresponding log-probability. For a fixed observed sequence under the model, these scores are also called its likelihood and log-likelihood. Later lessons will develop the full probability and estimation machinery; here the job is only to calculate and compare the two representations.
Candidate A has twice Candidate B’s product. Its log score is also larger: . That ordering is guaranteed because has base and is strictly increasing. “Larger” among negative log scores means closer to zero. The score did not become a probability after the logarithm; it became a comparison-friendly representation of one.
Binary64 reaches zero while the log score keeps moving
Computers cannot store every real number. JavaScript’s Number and NumPy’s
float64 use the binary64 floating-point format. NumPy reports its machine
limits through
numpy.finfo:
the smallest positive normal float64 value is about
. Positive subnormal values fill part of
the gap between that number and zero, but with reduced precision; the smallest
positive subnormal is about .
numpy.nextafter
confirms that this is the next representable float after zero in the positive
direction.
Move either slider with a pointer or arrow keys. The upper panel follows direct binary64 multiplication through the normal region, the narrow subnormal strip, and zero. The lower panel follows the finite additive value . The solid line with a circle and the dashed line with a square remain distinguishable without color, and the table exposes the selected state and transition rows.
Choose p from 0.01 to 0.50. Arrow keys change it by 0.01.
Choose 1 to 2,000 repeated factors. Arrow keys change the count by one.
- Direct binary64 product
- 0
- Cumulative log sum
- -921.034037
- Direct-product state
- Zero
- First subnormal factor count
- 308
- First zero factor count
- 324
For p = 0.10 repeated 400 times, the direct binary64 product is 0 (Zero); the cumulative log sum is -921.034037.
For p = 0.10 repeated 400 times, the direct binary64 product is 0 (Zero); the cumulative log sum is -921.034037.
Tiny direct products are rounded to four significant digits in this display. The table and state labels, not extra decimal places, identify the representability transition.
Show selected and boundary values as a table
| Factor count n | Direct product | Cumulative log sum | Direct-product state |
|---|---|---|---|
| 1 | 1.000e-1 | -2.302585 | Normal |
| 307 | 1.000e-307 | -706.893624 | Normal |
| 308 | 1.000e-308 | -709.196209 | Subnormal |
| 323 | 9.881e-324 | -743.734985 | Subnormal |
| 324 | 0 | -746.037570 | Zero |
| 400 | 0 | -921.034037 | Zero ← Selected |
| 2,000 | 0 | -4,605.170186 | Zero |
At the server-rendered starting state, and . Direct multiplication has already produced zero, but is finite. The log value retains an additive score for the positive factors. Calling in float64 still returns zero, because changing representation cannot create a positive float64 value below the format’s range.
The precise transition depends on the data type, values, and order of floating- point operations. The explorer deliberately models repeated binary64 multiplication; it is not a universal cutoff for every probability program.
NumPy mirrors the safe path
The following program was run with NumPy 2.5.2. Direct multiplication uses
np.prod, while log-space accumulation uses the element-wise natural logarithm
documented by numpy.log
followed by a sum.
import numpy as np
for n in (323, 324, 400, 401):
factors = np.full(n, 0.1, dtype=np.float64)
direct = np.prod(factors)
log_score = np.log(factors).sum()
print(f"n={n}: direct={direct:.4e}, log_score={log_score:.6f}")
limits = np.finfo(np.float64)
print(f"smallest normal: {limits.smallest_normal:.4e}")
print(f"smallest subnormal: {limits.smallest_subnormal:.4e}")
print(f"next after zero: {np.nextafter(0.0, 1.0):.4e}")
n=323: direct=9.8813e-324, log_score=-743.734985
n=324: direct=0.0000e+00, log_score=-746.037570
n=400: direct=0.0000e+00, log_score=-921.034037
n=401: direct=0.0000e+00, log_score=-923.336622
smallest normal: 2.2251e-308
smallest subnormal: 4.9407e-324
next after zero: 4.9407e-324
The 400- and 401-factor products collide at stored zero, while their log scores remain ordered. In practice, a system that needs to compare candidate products can keep the log scores and choose the larger one without exponentiating each score. This is the narrow numerical benefit: positive multiplicative factors become finite additive scores. It does not repair invalid inputs, rounding in every other operation, or a final conversion whose result is too small for the chosen type.
Adding alternative probabilities requires another identity. If and , then
not . NumPy’s
numpy.logaddexp
computes that log-of-a-sum directly. For two already logged alternatives,
and :
x, y = -1000.0, -1001.0
with np.errstate(divide="ignore"):
naive = np.log(np.exp(x) + np.exp(y))
stable = np.logaddexp(x, y)
print(naive)
print(stable)
print(np.exp(stable))
-inf
-999.6867383124818
0.0
The naive route exponentiates too early, turning both alternatives into zero.
np.logaddexp preserves their finite combined log score. Exponentiating that
score still underflows, exactly as the final line shows. Use sum(log_factors)
for a product of positive factors; use logaddexp when adding
alternatives that are already represented by log values.
Boundaries worth making explicit
The real logarithm’s domain and base conditions prevent several common bugs:
| Input or claim | Real-log result | Why |
|---|---|---|
| , , | Valid | A unique real exponent exists |
| Undefined as a real logarithm | No finite exponent makes a positive base equal zero | |
| Undefined in the real-number setting | A valid real-log base raised to a real exponent stays positive | |
| Invalid base | for every , so there is no inverse function | |
| Invalid for this real-log definition | Real powers do not produce every positive argument consistently | |
| False in general | The right side equals |
For real arrays, NumPy follows floating-point conventions around this boundary:
np.log(0.0) returns -inf and signals a divide-by-zero condition, while
np.log(-1.0) returns nan and signals an invalid operation. These are useful
machine values, not permission to erase the mathematical distinction. A factor
that is genuinely probability zero contributes to the log score; a
positive product that rounded to floating-point zero should have been logged
before multiplication. Once a computed product is already zero,
np.log(product) cannot reconstruct the lost factors.
Silently replacing zeros with a small positive constant also changes the model’s stated values. If clipping is an intentional modeling decision, record the rule rather than presenting it as exact arithmetic.
Finally, ranking direction depends on the base. For every base —including , , and —the logarithm is increasing, so the larger positive product has the larger log value. A valid base between zero and one gives a decreasing logarithm and reverses that ordering. Log-probability implementations normally use , which is why the less-negative log score ranks higher.
A finite score can be the useful result
The opening sequences did not need their microscopic probabilities converted back to decimal form to remain distinguishable. Their log scores preserved the multiplicative comparison as ordinary addition, and the product, quotient, and power laws explain why that representation works.
This foundation will support later lessons on probability, likelihood-based estimation, entropy, and stable model calculations. The next curriculum step changes focus to equations as constraints and the sets of values that satisfy them. For now, the practical stopping point is exact: keep positive factors in log space while combining and comparing them, and return to probability space only when the result is both necessary and representable.
Check your understanding
Question 1
Evaluate log₂(32) and log₁₀(0.001), then check each answer with a power.
Show the step-by-step solution
For , ask which exponent on produces :
For , rewrite the decimal as a power of ten:
Both arguments are positive, and the bases and are positive and not equal to , so the real logarithms satisfy the required assumptions. The checks are the powers and .
Question 2
For x > 0 and y > 0, expand ln(x³/y²) into logarithms of x and y, naming the law used at each step.
Show the step-by-step solution
Start with the quotient law because the outer operation divides two positive quantities:
Then use the power law on each term:
The assumptions and make , , and the quotient positive; they also ensure . The expanded expression therefore has the same real domain as the original expression under the stated assumptions.
Question 3
A teammate writes ln(4 + 5) = ln(4) + ln(5). Disprove the claim and state the correct product identity.
Show the step-by-step solution
Evaluate what each side represents. The left side is
The sum on the right uses the product law:
Because , their natural logarithms are unequal. Numerically, while . The valid identity is
for and . It converts multiplication, not addition, into a sum.
Question 4
A three-token candidate has positive factors 0.5, 0.2, and 0.1. Compute its direct product and natural-log score step by step, then convert the log score back.
Show the step-by-step solution
Multiply from left to right:
For the log representation, calculate and add the three terms:
The product law says this sum equals . Applying the inverse exponential gives
The conversion agrees with the direct product; the small difference implied by the displayed decimals comes only from rounding the log terms to six decimal places.
Question 5
Two candidates have natural-log scores −40 and −42. Which product is larger, and by what multiplicative factor?
Show the step-by-step solution
The natural logarithm uses base , so it preserves ordering. Since , the candidate with log score has the larger positive product.
Let the products be and . Their ratio uses the quotient rule for exponents:
Thus the first candidate’s product is about times the second’s. The two-point difference in log space is a multiplicative ratio in the original space.
Question 6
At p = 0.1, the explorer shows a subnormal direct product at n = 323 and zero at n = 324. What happens to the log score, and what does this say about exponentiating it?
Show the step-by-step solution
The additive score is . With :
Both are finite and remain different, even though direct binary64 multiplication reaches zero at 324 factors in the verified example. Log-space accumulation can therefore still compare the positive-factor sequences.
However, exponentiating asks float64 to represent approximately , below its positive range after rounding, so the stored result is zero. The log representation preserves the finite score; it does not expand the output range of binary64.
Question 7
Debug this code for adding two logged alternatives: np.log(np.exp(-1000) + np.exp(-1001)). Why does it return −inf, and which NumPy operation preserves the finite combined log score?
Show the step-by-step solution
The code exponentiates first. In float64, both intermediate values are too small to represent:
The program then computes , which NumPy represents as
-inf while signaling divide by zero.
Use the operation designed for alternatives already in log space:
combined = np.logaddexp(-1000.0, -1001.0)
# -999.6867383124818This computes without first rounding both
exponentials to zero. It is not the product rule: a product of positive factors
uses np.log(factors).sum(), while this example adds two alternatives. Finally,
np.exp(combined) still returns 0.0; the finite combined score is preserved,
but its probability-scale value remains unrepresentable in float64.