Why a deterministic machine wants randomness at all
By the end of the previous rung you saw the wall that grid methods hit: integrate over a region by laying down a grid of m points per axis, and in d dimensions that costs m^d points — the curse of dimensionality. Around dimension five or six, every classical quadrature rule is simply dead. This whole rung is built around the one method that walks straight through that wall: instead of marching through space on a regular grid, you throw darts at random and average what you hit. That is Monte Carlo, and its error falls only like O(1/sqrt(N)) — painfully slow in one dimension — but, crucially, that rate does not depend on the dimension at all.
But throwing darts at random presumes you have randomness, and here is the awkward truth this guide exists to face: a computer has none. Every instruction it executes is deterministic. Feed it the same inputs and it returns the same outputs, every single time — that is exactly the property that makes it a reliable calculator. There is no genuine coin-flip hiding inside the silicon. So before any of the methods in this rung can run, we must answer a sharp question: where do the 'random' numbers come from, if the machine itself is incapable of being surprised?
The answer is a deliberate, useful fraud. We give up on true randomness and manufacture a sequence that is fully determined by a formula yet behaves statistically like random numbers — no clumping, no detectable pattern, the right proportions in every range. Such a sequence is called pseudorandom, and the little algorithm that spits it out is a pseudorandom number generator, or PRNG. The word to hold onto is the prefix: pseudo. These numbers only pretend.
Inside the simplest generator: one formula, fed back into itself
The cleanest way to see how fake randomness is made is the oldest workhorse, the linear congruential generator (LCG). It keeps one integer of state, call it x_n, and produces the next one by a single line you could compute by hand: x_{n+1} = (a*x_n + c) mod m. Multiply by a constant a, add a constant c, then take the remainder after dividing by a modulus m so the value wraps back into the range 0 to m-1. To turn each integer into a fraction in [0, 1) you just divide by m. That is the entire engine — one multiply, one add, one remainder.
Linear congruential generator (LCG):
x_{n+1} = (a * x_n + c) mod m
u_{n+1} = x_{n+1} / m # a fraction in [0, 1)
seed: x_0 chosen by the user
a, c, m: fixed constants of the generator
Same seed -> exactly the same sequence, forever.Notice what is doing the work: each output is fed straight back in as the next input. The stream is one long chain, every link forced by the one before it. That is why the very first value matters so much. The starting state x_0 is the seed, and it alone selects which sequence you get. Fix the seed and you fix the entire infinite stream — give the generator the same seed tomorrow and it replays the identical numbers in the identical order. This is not a bug; as we will see, it is one of the most valuable features the whole scheme has.
Because the state is one integer that can only take m possible values, the chain must eventually revisit a value it has already produced — and the moment it does, the whole sequence repeats from there. The length before it loops is the period. A good LCG with a well-chosen a, c, and m achieves the maximum period m, visiting every value once before cycling. A carelessly chosen one can have a laughably short period or, worse, leave glaring structure in the output. The famous cautionary tale is IBM's RANDU from the 1960s: its 'random' triples, when plotted as points in 3D, all fell neatly onto just fifteen parallel planes. It was random-looking in one dimension and visibly crystalline in three.
What 'good' randomness actually means here
Since we have abandoned true randomness, we need an honest replacement standard. We do not ask whether the numbers are 'really' random — they provably are not — we ask whether they are statistically indistinguishable from random for the use at hand. Concretely a good generator wants three things: a uniform spread (every sub-interval of [0, 1) gets its fair share of values), independence (knowing past values gives no useful clue about the next), and a period so long you will never reach the end of it in your computation. The RANDU disaster failed the second test catastrophically: its values were uniform one at a time but violently dependent when grouped in threes.
How do you check this without a guarantee of randomness to compare against? You subject the stream to a battery of statistical tests — counting how often runs of increasing values occur, measuring correlations at many lags, binning the values in high-dimensional cubes to catch hidden planes like RANDU's. Modern test suites (the TestU01 'BigCrush' battery is the standard) run dozens of such probes. A generator is declared good not because it is truly random but because it survives every test we know how to write. That is a humbler, more honest claim, and it is the right one.
The generator most languages reach for today is the Mersenne Twister. It keeps a large state (624 integers, not one) and stirs it with a more elaborate recurrence, which buys it an astronomically long period — 2^19937 - 1, far longer than any computation will ever consume — and excellent uniformity across many dimensions, so it dodges the planar artefacts that sank RANDU. It is the workhorse behind a great deal of scientific Monte Carlo. Honesty demands one footnote, though: the Mersenne Twister is not cryptographically secure. Observe enough of its output and you can reconstruct its internal state and predict the rest. For our purposes — integration, simulation, sampling — that is irrelevant; for generating secret keys it would be a serious flaw. Match the generator to the job.
The hidden upside of being deterministic
It is tempting to read 'the numbers aren't really random' as a weakness to apologise for. It is the opposite. Determinism — the fact that the same seed replays the identical stream — is precisely what makes scientific computing with randomness trustworthy. A Monte Carlo simulation that uses true physical randomness could never be re-run; if it crashed at hour nine, or produced a suspicious result, you could never reproduce the exact run to debug it. A pseudorandom run can be replayed bit-for-bit by simply recording the seed.
This is reproducibility, and in this rung it is not a luxury — it is the difference between an experiment and a guess. Report a Monte Carlo result in a paper and a reader must be able to recreate your exact numbers; record the seed and they can. Compare two algorithms fairly by feeding them the same random stream so the only difference is the algorithm, not the luck of the draw — a trick called common random numbers that quietly sharpens nearly every comparison. None of this would be possible with true randomness. The cheat is the feature.
From a uniform stream to everything else
Everything so far produces one specific thing: a stream of numbers uniform on [0, 1). That is the universal raw material, and it is all a PRNG ever needs to give you. But the methods ahead rarely want plain uniform numbers — they want samples from a bell curve, an exponential decay, a lopsided custom distribution. The pleasant surprise, and the subject of the very next guide, is that every such distribution can be built out of that single uniform stream by a clever transformation. The uniform generator is the faucet; sampling is the plumbing that reshapes its water into any distribution you like.
It is worth naming a road not taken in this rung, because it sits right beside ours. Once you accept that what you really want is points that fill space evenly rather than points that are independent, you can drop the pretence of randomness entirely and use a low-discrepancy sequence — a cleverly non-random point set engineered to avoid the clumps and gaps that genuine randomness inevitably leaves. Feeding those into Monte Carlo gives quasi-Monte Carlo, which can converge faster than O(1/sqrt(N)) on smooth problems. We meet it later; flag it now only to underline that 'random' was always a means, never the goal. The goal is good coverage of space.
So here is the honest summary of what a generator is and is not. It is a deterministic recurrence — usually just a state stirred by a fixed formula — whose output is engineered to pass every statistical test for randomness yet replays perfectly from a seed. It is not a source of true randomness, not magic, and not always fit for security. Hold those two facts together: the numbers are fake, and that fakeness is exactly what makes the rest of this rung both possible and trustworthy. With a reliable uniform faucet in hand, you are ready to learn how to shape its output into any distribution you need.