Probability
Language revisions
- C++20
- The <random> engines and distributions are stable and reproducible; std::uniform_random_bit_generator is a concept.
- C++23
- std::generator supports lazy sample streams without an allocation per sample.P2502R2
- C++26
- std::simd enables vectorized generation and evaluation of independent streams.P1928
Definition
Probability spaces and random variables
Why the measure-theoretic setting is worth keeping
For finite sample spaces the machinery is unnecessary, and for the continuous ones that occur in simulation it is not: without it there is no coherent account of conditioning, of limits of sequences of random variables, or of the stochastic integrals that stochastic differential equations are defined by. The setting also supplies the notion of a -algebra as the information available at a point in time, which is what makes filtrations and hence path-dependent simulation precise.
Variance and its additivity
The variance is , and for independent variances add. That single fact is what produces the rate that governs every Monte Carlo method, and it is also what makes variance reduction the only lever available: the rate is fixed, so only the constant can be changed.
Independence and its computational meaning
Independence is a statement about the measure. In computation it becomes a statement about streams: two sequences of pseudorandom numbers are treated as independent when no statistical test in use distinguishes them from independent samples. This is a weaker and more fragile notion than the mathematical one, and it is why parallel Monte Carlo requires deliberate stream splitting rather than sharing one generator.
Modes of convergence
Three modes are used, and they are not interchangeable.
In probability
for every . This is what the weak law of large numbers gives, and it is enough to justify a single estimate at a single sample size.
Almost surely
. This is what the strong law gives, and it is what justifies treating one long run as representative rather than needing independent repetitions.
In distribution
for bounded continuous . This is what the central limit theorem gives, and it is the basis of confidence intervals.
The finite-variance hypothesis is where practical trouble enters: for heavy-tailed integrands the sample variance does not converge, the confidence interval computed from it is meaningless, and the failure is silent. The Berry-Esseen theorem quantifies the rate of approach, with a constant involving the third absolute moment, which is why intervals from small samples of skewed distributions are unreliable even when the variance is finite.
Distributions that recur
| Distribution | Where it appears | Sampling method |
|---|---|---|
| Uniform on | The primitive from which others are built | Bit manipulation of the generator output |
| Normal | Errors, diffusions, random projections | Box-Muller, Ziggurat |
| Exponential | Waiting times, Poisson processes | Inverse transform, |
| Poisson | Event counts | Knuth's product method, or inversion |
| Discrete with outcomes | Resampling, mixtures | Alias method, per sample |
| Multivariate normal | Gaussian processes, sketching | Cholesky factor times a normal vector |
The alias method is worth naming because it is the case where the obvious algorithm, a linear or binary search over a cumulative distribution, is asymptotically worse than necessary: or per sample against after preprocessing.
Motivation
Randomness enters numerical computing in three distinct ways, and conflating them causes errors.
As a model of the problem
Stochastic differential equations, Monte Carlo integration of high-dimensional integrals, and uncertainty quantification. Here the randomness is part of the specification and the answer is a distribution or a functional of one. Reproducibility is a testing convenience, not a correctness requirement.
As an algorithmic device on a deterministic problem
Randomised low-rank approximation, sketching for least squares, randomised pivoting, hashing. Here the input is deterministic and the algorithm's guarantees are probabilistic, holding with high probability over its internal randomness.
The distinction matters for testing: such an algorithm may be rerun with a different seed, and a failure that does not recur is a probabilistic event rather than a defect. It also matters for reporting: a result without its failure probability is as incomplete as a numerical result without its error bound.
As an error model
Rounding errors treated as independent random variables give estimates instead of the worst-case bounds of Numerical Analysis. This use is heuristic, since rounding errors are deterministic functions of the data, but it predicts observed behaviour far better than the worst-case bound, and it is the reason worst-case bounds are used to establish scaling rather than to predict magnitudes.
Formal formulation
Monte Carlo integration
Monte Carlo integration estimates by
so the root-mean-square error is , independent of dimension.
The dimensional comparison
Against a tensor-product rule of order in dimensions, which needs points:
| Tensor product, | Monte Carlo | |
|---|---|---|
| 2 | ||
| 4 | ||
| 8 | ||
| 16 | ||
| 100 |
The crossover at is the whole case for Monte Carlo, and it explains why the method is standard in finance and statistical physics and rare in one-dimensional quadrature.
Quasi-Monte Carlo
Low-discrepancy sequences replace random points with deterministic ones that fill the space more evenly, giving error by the Koksma-Hlawka inequality for integrands of bounded variation in the sense of Hardy and Krause. The improvement is real for moderate and smooth integrands, and it disappears as grows because of the factor.
Randomised quasi-Monte Carlo, which applies a random shift to the sequence, recovers an unbiased estimator with a computable error estimate while keeping most of the improvement. Without the randomisation there is no error estimate at all, which is the practical reason it is used.
Concentration inequalities
Concentration inequalities convert variance into probabilistic bounds, and they are what turn a Monte Carlo estimate into a statement with a confidence level.
The basic bounds
For independent with and , Bernstein's inequality gives
and Hoeffding's inequality for gives
Bernstein's bound is the sharper of the two when the variance is small relative to the range, which is the usual case for a well-designed estimator. It is what makes variance reduction pay twice: once in the estimate and once in the width of the interval.
Why they beat Chebyshev
Chebyshev's inequality gives a bound decaying polynomially in , and the exponential bounds above decay exponentially. The difference is what makes high-confidence statements affordable: to reach failure probability , Chebyshev needs samples and Hoeffding needs . Confidence of costs a billion samples under the first and a factor of about twenty under the second.
Randomised numerical linear algebra
For matrices, the corresponding tool is the matrix Bernstein inequality, which gives randomised low-rank approximation its guarantee.
Why the structural gain exceeds the asymptotic one
The optimal rank- error is by the Eckart and Young theorem of Linear Algebra, so the randomised method is within a modest factor at cost rather than .
The more important gain is structural. The randomised algorithm touches only through matrix-matrix products, so it is compute-bound and parallel, whereas a classical rank-revealing factorization is a sequence of dependent level-2 operations. It also requires only one or two passes over , which makes it applicable when does not fit in memory at all.
Power iteration for slowly decaying spectra
When the singular values decay slowly the basic method is inaccurate, and the standard remedy replaces by , which raises the singular values to the power and separates them. Two or three power iterations suffice in practice, each costing two more passes over , and the orthonormalisation between iterations is required because the powers otherwise collapse numerically onto the dominant direction.
Random projections
The dimension of the target depends on the number of points and not on the original dimension, which is the property that makes sketching viable. The same construction underlies sketched least squares, where an problem is replaced by an one at the cost of a controlled loss in the residual.
C++ representation
Generators and distributions
#include <cmath>
#include <concepts>
#include <cstddef>
#include <random>
namespace hpc {
template <class G>
concept RandomBitGenerator = std::uniform_random_bit_generator<G>;
// A distribution over T: sampling requires a generator, never a global one.
template <class D, class G>
concept Distribution =
RandomBitGenerator<G> &&
requires(D& d, G& g) {
typename D::result_type;
{ d(g) } -> std::same_as<typename D::result_type>;
};
// Semantic requirements:
// S1. Successive calls to d(g) are independent given g's state.
// S2. The generator is not shared between threads without synchronisation.
// S3. Reproducibility requires the seed, the engine, and the exact sequence
// of calls, so any change to the call pattern changes the results.
} // namespace hpc
The fragility of reproducibility
The third obligation is the one most often violated. Adding a single extra sample inside a loop, even one whose value is discarded, changes every subsequent value and therefore every result. This makes seemingly harmless refactoring a source of unreproducible output, and it is the reason counter-based generators, whose output is a pure function of a key and a counter, are preferred where reproducibility matters.
Distributions are not portable
The standard specifies the engines exactly and the distributions only by their statistical
properties, so std::normal_distribution may produce different values on different
implementations from the same seed. Code that must reproduce results across toolchains implements
its own transformations from the uniform generator rather than relying on the library
distributions.
Estimates carry their uncertainty
#include <cmath>
#include <cstddef>
namespace hpc {
struct estimate {
double mean;
double standard_error;
std::size_t samples;
// Asymptotic normal interval. Valid only when the integrand has finite
// variance and n is large enough for the central limit theorem to apply.
constexpr double half_width(double z = 1.96) const noexcept {
return z * standard_error;
}
};
template <class F, RandomBitGenerator G>
estimate monte_carlo(F&& integrand, G& generator, std::size_t n) {
double mean = 0.0;
double m2 = 0.0;
for (std::size_t i = 1; i <= n; ++i) {
const double x = integrand(generator);
const double delta = x - mean;
mean += delta / static_cast<double>(i);
m2 += delta * (x - mean);
}
const double variance = n > 1 ? m2 / static_cast<double>(n - 1) : 0.0;
return {mean, std::sqrt(variance / static_cast<double>(n)), n};
}
} // namespace hpc
Why Welford rather than sums of powers
Welford's recurrence is used rather than accumulating and , because the latter subtracts two large nearly equal quantities and loses all significance when the mean is large relative to the standard deviation. For near with standard deviation , the sum of squares computation in binary64 retains about four digits of the variance; Welford's retains all of them. This is a cancellation problem of exactly the kind analysed in Numerical Analysis, appearing in a routine that looks like bookkeeping rather than numerics.
Implementation
Independent, reproducible streams
Parallel Monte Carlo requires streams that are independent and reproducible. Splitting a single generator by seeding from a counter is the reliable construction; sharing one engine across threads is a data race, and seeding from the clock destroys reproducibility.
#include <cstdint>
#include <random>
#include <vector>
namespace hpc {
// One independent, reproducible stream per worker, derived from a single root
// seed by a sequence-dependent seeding scheme.
inline std::vector<std::mt19937_64> split_streams(std::uint64_t root_seed,
std::size_t workers) {
std::vector<std::mt19937_64> engines;
engines.reserve(workers);
for (std::size_t w = 0; w < workers; ++w) {
std::seed_seq seq{root_seed, static_cast<std::uint64_t>(w)};
engines.emplace_back(seq);
}
return engines;
}
} // namespace hpc
Counter-based generation
Counter-based generators such as Philox are the better construction where they are available: the stream is a pure function of a key and a counter, so independence is by construction rather than by a seeding heuristic, there is no state to displace cache, the generator vectorises, and a simulation can be restarted at an arbitrary point without replaying the sequence. The last property is what makes checkpointing a stochastic simulation practical.
Combining partial estimates
Reduction of per-worker estimates must combine means and variances rather than concatenating samples, using the parallel form of Welford's update:
namespace hpc {
// Associative and numerically stable: the combination is order-independent up
// to rounding, so it may be applied in any reduction tree.
constexpr estimate combine(const estimate& a, const estimate& b) noexcept;
} // namespace hpc
The associativity is what allows the combination to be used as the operator of a parallel reduction in the sense of Algebra, so a Monte Carlo run over workers is a monoid reduction over partial estimates.
Variance reduction
Variance reduction changes the constant in a rate that cannot be improved, and it is therefore worth more than any implementation tuning.
Control variates
Subtract a correlated quantity with known mean: , with optimal , reducing the variance by the factor . A correlation of is a tenfold reduction in variance and hence a hundredfold reduction in samples.
Antithetic variates
Pair each sample with its reflection , which removes the odd component of the integrand exactly and cannot increase the variance for monotone integrands. The cost is nothing beyond the pairing.
Importance sampling
Sample from a distribution concentrated where the integrand is large, weighting by the likelihood ratio. The variance can be reduced by orders of magnitude and can also be made infinite by a poor choice of proposal, which is why the weights are monitored: an effective sample size far below the nominal one is the signature of a bad proposal.
Stratification
Partition the domain and allocate samples per stratum. It cannot increase the variance, and with proportional allocation it removes the between-stratum component entirely, which for smooth integrands is most of it.
Complexity
| Operation | Time | Space | Remarks |
|---|---|---|---|
| Monte Carlo to RMSE ε | Θ(σ²/ε²) samples | Θ(1) | Dimension-independent |
| Quasi-Monte Carlo, smooth integrand | Θ(ε^{−1}(log n)^d) | Θ(d) | Degrades with dimension d |
| Tensor-product quadrature | Θ(ε^{−d/p}) | Θ(1) | p = order; infeasible for d above about 6 |
| Randomised rank-k SVD | Θ(mn(k+p)) | Θ(m(k+p)) | Against Θ(mn²) for a full SVD |
| Randomised SVD with q power iterations | Θ((2q+1)mn(k+p)) | Θ(m(k+p)) | Needed for slow spectral decay |
| Johnson–Lindenstrauss projection | Θ(Ndk) | Θ(Nk) | k = O(ε⁻² log N) |
| Welford update | Θ(1) | Θ(1) | Numerically stable |
| Sum-of-squares variance | Θ(1) | Θ(1) | Catastrophic cancellation |
| Mersenne Twister sample | Θ(1), large state | 2.5 KB per stream | Displaces cache |
| Counter-based sample | Θ(1), no state | Θ(1) | Vectorises; restartable |
| Alias-method discrete sample | Θ(1) | Θ(k) | After Θ(k) preprocessing |
| Inverse-CDF discrete sample | Θ(log k) | Θ(k) | Binary search |
Performance considerations
Generation often dominates
Random number generation is frequently the bottleneck in Monte Carlo codes, not the integrand.
std::mt19937_64 produces one 64-bit value per call with a 2.5 KB state that displaces useful data
from cache. Counter-based generators produce a value from a key and a counter with no state,
vectorise across lanes, and give reproducible streams by construction.
Accuracy is expensive, so variance reduction is the lever
The rate means one more digit costs a hundredfold increase in samples. Variance reduction changes and is therefore worth more than any implementation tuning, since it improves the constant in a rate that is fixed for the method class.
Scaling results from Monte Carlo prove little
Monte Carlo parallelises with essentially no communication: each worker accumulates its own partial estimate and the reduction is at the end. This makes it the standard demonstration of near-linear scaling, and also the reason such demonstrations say little about a machine's behaviour on communication-bound problems.
Sampling non-uniform distributions
Sampling from non-uniform distributions is dominated by rejection rates and by transcendental function calls. The Ziggurat method for normal variates avoids both in the common case, at the cost of a table and a rare branch that breaks vectorization when it is taken. For vectorized code the Box-Muller transform is often preferable despite being slower scalar, because it is branch-free and therefore uniform across lanes.
Divergence across lanes
Any rejection method diverges: some lanes accept and some do not, so a vectorized implementation either masks and retries, wasting work, or falls back to scalar. Methods with a fixed operation count per sample are worth a substantial factor in vectorized code even when they are slower in isolation, and this is the same lane-divergence argument that appears in SIMD.
Limitations
Pseudorandom generators are deterministic. Statistical tests can detect bad ones but cannot certify a good one, and a generator adequate for simulation may be inadequate where adversarial inputs are possible.
Confidence intervals from the central limit theorem are asymptotic and are unreliable for heavy-tailed integrands, where the sample variance itself may not converge. Checking the tail behaviour of the integrand is part of using the method, not an optional refinement.
Probabilistic guarantees for randomised algorithms hold with a stated failure probability, which is a different kind of statement from a deterministic bound and must be reported as such.
Reproducibility across machines is not automatic even with a fixed seed: floating-point summation order, thread counts, vector widths and library distribution implementations all affect the result. Where bitwise reproducibility is required, the reduction tree must be fixed and the distributions implemented locally.
Importance sampling can increase the variance without any diagnostic unless the weights are monitored, and the failure is silent in exactly the regime where the method was expected to help.
Related entries
Numerical Analysis for the statistical error model; Numerical Integration for the deterministic alternatives; Linear Algebra for the approximation theorem behind randomised factorization; Algebra for the monoid structure of estimate combination; Parallelism for the reduction structure.
References
- R. Durrett, Probability: Theory and Examples, 5th ed., Cambridge University Press, 2019.
- N. Halko, P.-G. Martinsson and J. Tropp, Finding Structure with Randomness, SIAM Review 53(2), 2011.
- J. Tropp, An Introduction to Matrix Concentration Inequalities, Foundations and Trends in Machine Learning 8, 2015.
- B. Welford, Note on a Method for Calculating Corrected Sums of Squares and Products, Technometrics 4(3), 1962.
- J. Salmon, M. Moraes, R. Dror and D. Shaw, Parallel Random Numbers: As Easy as 1, 2, 3, SC11.
- A. Owen, Monte Carlo theory, methods and examples, 2013.
- G. Marsaglia and W. Tsang, The Ziggurat Method for Generating Random Variables, Journal of Statistical Software 5(8), 2000.