Generators FIELD NOTES · 4 MIN READ
How Pseudorandom Numbers Work
Why computers fake randomness: seeds, linear congruential generators, uniform distributions and modulo bias, and Math.random vs crypto RNG.
A computer has no dice to roll — it only follows instructions, and instructions give the same output for the same input every time. So when a program needs a "random" number, it computes one: a deterministic formula produces a stream that looks patternless. Those are pseudorandom numbers, and knowing how they're made tells you exactly when they're good enough and when they aren't.
True randomness versus pseudorandomness
True random numbers come from measuring physical noise — thermal jitter in circuits, timing of your keystrokes, quantum events — where no formula can predict the next value. Pseudorandom numbers come from an algorithm: a function churns an internal state and emits a number derived from it, then updates the state. Given the same starting state, called the seed, the same sequence comes out every time. That reproducibility is a feature when you want it (replaying a test, verifying a raffle, sharing a seeded game world) and a liability when you don't (anything an adversary could profit from predicting).
A toy generator you can do by hand
The classic building block is the linear congruential generator (LCG), used by many early programming libraries:
X ← (a·X + c) mod m with a = 7, c = 1, m = 10, seed X = 3
Run it: 7 × 3 + 1 = 22 → 22 mod 10 = 2. Then 7 × 2 + 1 = 15 → 5. Then 36 → 6, then 43 → 3, and the next step returns 2 again. The whole stream is 2, 5, 6, 3, 2, 5, 6, 3 … a loop of just four values. Every LCG cycles eventually, and this toy one makes the problem visible: the loop is short and the "randomness" is a fixed dance. Real generators use enormous constants — moduli like 2^31 − 1 or 2^64, and the widely used Mersenne Twister has a period of 2^19937 − 1 — so the loop is far too long to notice. But the principle stands: it's arithmetic, not dice.
Seeds: one input, one stream
A seed is the starting state of the generator. Same seed, same numbers, forever — which is why seeded randomness powers reproducible simulations, snapshot tests, and rollback-safe games. Typically a program seeds itself with something unpredictable, like the current time in milliseconds, so each run differs. Some tools expose the seed deliberately: a seeded dice roll, for instance, can be re-run and verified by anyone with the same seed instead of trusted on faith.
Uniform by design — and the modulo trap
A good generator is uniform: over its period, every value appears with equal frequency, so mapping its output to "1 to 6" should give each face exactly 1/6. The mapping is where naive code goes wrong. A common shortcut, rand() % 6, divides the generator's raw range by 6 and keeps the remainder — but the raw range rarely divides evenly. A 32-bit generator produces 4,294,967,296 values; 4,294,967,296 mod 6 = 4, so remainders 0–3 each occur 715,827,883 times while remainders 4–5 occur only 715,827,882 times. A one-count-in-700-million bias: invisible in a board game, real in a Monte Carlo simulation or a lottery drawing. Quality libraries use rejection sampling — discard the values that would unbalance the range. Uniformity also compounds nicely: sum many uniform dice and the totals cluster into the bell curve every tabletop player knows.
Math.random versus cryptographic randomness
JavaScript's Math.random() is a fast, seedless pseudorandom generator — good for games, animations, and sampling, and not designed to withstand an attacker. Today's engines use solid algorithms (V8 uses xorshift128+), but the outputs are derivable: with a little state from the stream, later outputs can be reconstructed. crypto.getRandomValues() is different: it draws from the operating system's cryptographically secure generator, seeded continuously from true physical entropy and built so that predicting the next value — even knowing every previous one — is computationally infeasible.
The rule of thumb: if nobody benefits from guessing your numbers, Math.random is fine; if someone could (raffle winners, tokens, anything security-adjacent), insist on the crypto source. A shuffle that decides a real winner needs that guarantee, because the Fisher–Yates shuffle is only as fair as the randomness fed into it.
Try it yourself
The Random Number Generator uses crypto-grade randomness from your browser to produce one or many numbers in any range, with an option for unique values. The Dice Roller rolls any count and shape of dice — d6 to d100 — and reports each roll, total, and average, with reproducible rolls via an optional seed. And the Randomizer applies a Fisher–Yates shuffle to any list or picks N unique items, powered by your browser's own pseudorandom stream.