Simulation & Monte Carlo
When an expectation has no closed form — a path-dependent option, a drawdown distribution, a posterior — you estimate it by sampling. Monte Carlo turns every integral into an average, and the entire subject reduces to two questions: how do I draw from the distribution I need? and how do I shrink the variance of the average? This chapter derives the estimator and its error law, builds the classic sampling algorithms (inverse transform, acceptance–rejection, Box–Muller, Cholesky), and ends with importance sampling — the tool that makes rare-event probabilities computable.
Any expectation is an integral, and any integral over a probability density is an expectation. If you can draw samples from the density, the law of large numbers (chapter 7) guarantees the sample average of converges to , and the CLT tells you exactly how fast. The magic is what the error rate does not depend on: the dimension of the integral. A 100-dimensional basket-option price converges at the same rate as a one-dimensional one — which is why Monte Carlo owns high-dimensional finance while quadrature grids die of the curse of dimensionality.
The Monte Carlo estimator and its error#
Suppose you want and can simulate iid copies of . The Monte Carlo estimator is the plain average
By independence, variances add: where . So the root-mean-square error is
and by the CLT, for large , giving the reportable interval with the sample standard deviation of the . Nothing in the derivation mentioned the dimension of — only the variance of the scalar matters. The price of the square root: one more decimal digit of accuracy costs the samples. Every variance-reduction technique below exists to shrink instead of growing .
Worked example — estimating . Throw uniform points on the unit square; has mean , a Bernoulli with variance . The estimator therefore has standard error . With darts: se — you get reliably, but the fourth digit is already a coin flip. To pin down (se ) you would need darts. Monte Carlo is a blunt instrument for precision — and a scalpel for dimension.
Inverse transform sampling#
Every sampler starts from uniforms — that is what a random number generator emits. The inverse transform method converts them into any distribution with a computable quantile function: if and is a CDF with generalised inverse , then has CDF .
For any , the event is exactly : if then is in the set whose infimum defines , so ; conversely implies by right-continuity and monotonicity of . Hence
since . This is the same probability integral transform proved in order statistics — there it turned data into uniforms (p-values); here it runs in reverse, turning uniforms into data.
Worked example — exponential. For , solve to get , and since , the one-liner is . Concretely with : ; . The method also covers discrete distributions (step through cumulative probabilities until they exceed ) — which is the honest answer to the classic exercise “simulate from an arbitrary CDF.”

Acceptance–rejection#
When is unavailable but the density is computable, sample from an easy proposal density dominating : choose with for all , then repeat: draw and , and accept if .
The joint chance of proposing near and accepting is . Integrating over , the overall acceptance probability is . By Bayes, the density of given acceptance is
Exactly the target — and the number of proposals per accepted sample is geometric with mean . So the whole game is finding a proposal that hugs tightly: close to 1 means almost nothing is wasted. Worked numbers: to sample , , from a uniform proposal : the max of is , so and you accept of proposals — three draws for every two samples. In high dimensions typically blows up exponentially, which is why rejection is a low-dimensional tool.
Box–Muller and Cholesky: manufacturing normals#
The normal CDF has no closed-form inverse, so normals get their own trick. Box–Muller: from two independent uniforms ,
are independent standard normals.
Write a standard normal pair in polar form, . The joint density is rotationally symmetric, so independently of , and the squared radius satisfies
(the chi-square with 2 df from the distribution zoo). Both ingredients are inverse-transform-easy: and . Substituting back gives the formulas. Note the trap this exposes: to get a uniform point on a circle, take — but a uniform point in a disk needs , not , because area grows like .
Correlated normals via Cholesky. Portfolios need normals with a prescribed covariance . Factor (lower-triangular , which exists because covariance matrices are PSD — see joint distributions) and set for iid standard normals . Then , and is normal because linear combinations of normals are normal. In the correlation case the factorisation is worth memorising: solving
Check it: and . With : — the triangle of correlated simulation. This one line is the seed of every correlated-asset simulator, and the regression-line structure it encodes is exactly the bivariate-normal conditional expectation derived in chapter 5.
Importance sampling: buying variance with bias-free money#
The naive estimator fails exactly where finance cares most: rare events. To estimate for , naive sampling waits ~31,600 draws per hit. Importance sampling samples where the action is and reweights. For any proposal density that is positive wherever ,
so the weighted average with likelihood ratio is unbiased — that one-line change of measure is the whole proof. The art is choosing to shrink the variance of ; the theoretical optimum achieves zero variance for one-signed but requires knowing — so in practice you tilt toward it.
Worked example — the tail probability, tilted. Shift the sampling distribution to , centred on the rare region. The weight is , and now roughly half the draws land in instead of one in 31,600. The variance collapses by a factor of several thousand — the simulation below measures a standard error roughly 80 times smaller, i.e. about fewer paths for the same accuracy. This is how desks compute deep-tail VaR, CVA, and far-out-of-the-money option prices (extreme value theory is the model-based complement).

import math
import numpy as np
rng = np.random.default_rng(11)
n = 100_000
truth = 0.5 * math.erfc(4.0 / math.sqrt(2)) # P(Z > 4) = 3.167e-05
# Naive Monte Carlo: indicator of a rare event
z = rng.standard_normal(n)
naive = (z > 4.0).astype(float)
# Importance sampling: draw from N(4, 1), reweight by f/q = exp(-4y + 8)
y = rng.standard_normal(n) + 4.0
weighted = (y > 4.0) * np.exp(-4.0 * y + 8.0)
for name, s in [("naive", naive), ("importance", weighted)]:
est, se = s.mean(), s.std(ddof=1) / np.sqrt(n)
print(f"{name:>10}: {est:.3e} +/- {se:.1e} (truth {truth:.3e})")
# naive : 3.00e-05 +/- 1.7e-05 -- error the size of the answer
# importance: 3.17e-05 +/- 2.1e-07 -- ~80x smaller se => ~6,500x fewer pathsVariance reduction and the wider toolkit#
Importance sampling is one member of a family, all attacking rather than — the mechanics are developed in numerical methods:
- Antithetic variates: pair each path driven by with its mirror ; for monotone payoffs the pair’s errors negatively correlate and partly cancel.
- Control variates: simulate alongside a correlated quantity with knownmean (e.g. price an Asian option using the geometric-average Asian, which has a closed form, as control) and subtract the control’s error: .
- Stratification: force the samples to cover the space evenly (fixed counts per stratum), removing between-stratum randomness.
- Quasi-Monte Carlo: replace random draws with low-discrepancy sequences (Sobol); error decays near rather than in moderate dimension — standard in production option pricers.
Practice problems#
You have a uniform random generator and a CDF (possibly with jumps and flat stretches). Produce samples with distribution .
Solution. Return . The generalised inverse handles both pathologies: a jump of at (an atom) means a whole interval of maps to , reproducing the point mass ; a flat stretch (a gap in the support) is skipped because the infimum jumps across it. Proof of correctness is the equivalence , so . For a discrete list of probabilities, this is “walk the cumulative sums until they exceed ” — say that in one breath and you have answered both the continuous and discrete versions.
Estimate for standard normal by simulation. Why is the naive approach hopeless, and what do you do instead?
Solution. The truth is . Naive MC averages a Bernoulli() indicator, so its relative standard error is : for 10% relative accuracy you need , i.e. draws — and a 20-sigma event would need more paths than atoms in reasonable computers. Instead sample and average : unbiased by the change-of-measure identity, and now half the draws hit the region. The weight formula is just the ratio of normal densities: . Mentioning that the proposal must dominate the target’s tail — never tilt to a thinner-tailed proposal — is what separates a memorised answer from an understood one.
From iid standard normals , construct standard normal with correlation . Then: simulate two asset returns with vols and correlation .
Solution. — the 2×2 Cholesky factor of the correlation matrix. Verify in two lines: , . For returns, scale: . The standard escalation — “now do 3 assets” — wants the general answer: Cholesky-factor and set ; and the trap to flag is that a hand-built “correlation matrix” can fail to be PSD (e.g. three pairwise correlations of are impossible), in which case Cholesky fails — correctly.
You estimate by throwing uniform darts at the unit square and counting hits inside the quarter circle. How many darts for a standard error of ?
Solution. The hit indicator is Bernoulli with , so . Setting gives . The instructive follow-up: each extra decimal digit multiplies by 100 (the law), so Monte Carlo is the wrong tool for computing to ten digits but the right tool for a 100-dimensional integral — the error rate never sees the dimension.
How do you draw a uniform point (a) on the unit circle’s boundary, (b) inside the disk, (c) on the surface of the unit sphere? Where do naive answers go wrong?
Solution. (a) , point . (b) The trap: taking radius over-weights the centre, because the area inside radius grows like . Uniformity needs , so by inverse transform . (c) The trap: uniform latitude/longitude bunches points at the poles. Clean answers: draw iid normal and return — rotational symmetry of the Gaussian (the same fact behind Box–Muller) makes the direction exactly uniform in any dimension. Or rejection: sample the cube, keep points with , normalise — but note the acceptance rate ( in 3D) collapses exponentially with dimension, so the Gaussian trick is the one that scales.
Next: the mathematics is complete — now train it under fire. A playbook for attacking any probability problem on sight, the canonical constants, and a mixed problem gauntlet spanning the whole series: Problem-solving drills.

