Guide to Random Number Generation: How Randomness Works
Random numbers are everywhere in computing — from shuffling your playlist and generating passwords to running Monte Carlo simulations and securing encrypted connections. But how do computers, which are fundamentally deterministic machines, produce randomness? This guide explores the different types of random number generators, how they work, and when to use each one.
True Random vs Pseudo-Random
There are two fundamentally different approaches to generating random numbers:
True Random Number Generators (TRNGs)
True randomness comes from physical phenomena: radioactive decay, atmospheric noise, thermal noise in circuits, or mouse movements and keystroke timing. These sources are genuinely unpredictable — even with perfect knowledge of the current state, you can't predict the next value.
Examples: random.org (atmospheric noise), Intel's RDRAND instruction (thermal noise), Cloudflare's lava lamp wall (yes, really — they point cameras at lava lamps and use the images as entropy sources).
TRNGs are slow and hardware-dependent, so they're typically used to seed other generators rather than produce every random number directly.
Pseudo-Random Number Generators (PRNGs)
PRNGs use mathematical algorithms to produce sequences of numbers that appear random but are entirely deterministic. Given the same starting value (called a seed), a PRNG always produces the same sequence. This is actually useful — it makes results reproducible for testing and debugging.
The key insight: PRNG output is statistically random (passes randomness tests, has uniform distribution) but is theoretically predictable if you know the algorithm and seed.
How PRNGs Work
Most PRNGs follow a simple pattern: take a current state, apply a mathematical transformation, output a number, and update the state. The most common algorithms include:
Linear Congruential Generator (LCG)
The simplest and oldest PRNG: next = (a × current + c) mod m. Fast but has known weaknesses — sequential values are correlated, and the sequence repeats after at most m values. Used in many standard library rand() implementations.
Mersenne Twister
The most widely used PRNG, with a period of 219937-1 (a Mersenne prime — hence the name). Excellent statistical properties and very long period. Used as the default in Python, Ruby, PHP, and many other languages. However, it's not cryptographically secure — after observing 624 consecutive outputs, an attacker can predict all future values.
Xoshiro/Xoroshiro
Modern, fast PRNGs designed by Sebastiano Vigna. Very fast (just a few XOR and shift operations), good statistical quality, and small state. Popular in game engines and simulations where speed matters.
Cryptographically Secure PRNGs (CSPRNGs)
For security-sensitive applications — generating passwords, encryption keys, authentication tokens, session IDs — you need a CSPRNG. These have an additional guarantee: even if an attacker sees all previous outputs, they cannot predict the next one.
CSPRNGs achieve this by:
- Using entropy from the operating system (hardware noise, interrupts, disk timing)
- Applying cryptographic algorithms (AES-CTR, ChaCha20) to the entropy pool
- Regularly reseeding with fresh entropy
In practice, use these APIs:
// JavaScript (browser)
crypto.getRandomValues(new Uint32Array(1));
// JavaScript (Node.js)
const { randomInt } = require('crypto');
randomInt(1, 100);
// Python
import secrets
secrets.randbelow(100)
// Don't use Math.random() for security!
// It's a fast PRNG, not cryptographically secure.
Common Use Cases
Gaming and Simulations
Games need random numbers for loot drops, enemy behavior, procedural generation, and dice rolls. Speed matters more than cryptographic security here, so PRNGs like Xoshiro are ideal. Many games use seeded PRNGs so players can share and replay the same "random" world (Minecraft seeds, for example).
Cryptography and Security
Encryption keys, nonces, initialization vectors, session tokens, and password salts all require CSPRNGs. Using a weak RNG for cryptographic purposes is a critical vulnerability — the Debian OpenSSL disaster of 2008 (where a bug reduced the key space to just 32,767 possible keys) showed how devastating predictable randomness can be.
Statistical Sampling
Researchers use random numbers to select representative samples from populations, run Monte Carlo simulations (estimating pi, modeling stock prices, predicting weather), and perform randomized experiments. Here, statistical quality and reproducibility (seeds) matter most.
A/B Testing
Web applications use random assignment to split users into test groups. The randomization needs to be consistent per user (same user always sees the same variant) but uniformly distributed across the population.
Art and Music
Generative art, procedural music, and creative coding all rely on controlled randomness. Artists often use seeded PRNGs so they can reproduce and iterate on results they like.
Common Mistakes with Random Numbers
- Using Math.random() for security:
Math.random()is not cryptographically secure. Never use it for passwords, tokens, or keys. - Modulo bias:
rand() % ndoesn't give uniform distribution if the range doesn't evenly divide the generator's range. Use proper range functions instead. - Not seeding properly: Using a fixed seed or low-entropy seed (like the current second) makes output predictable.
- Assuming independence: Some PRNGs have correlations between sequential values. For multidimensional simulations, use generators designed for that purpose.
- Reusing random values: A nonce (number used once) should never be reused. A fresh random value should be generated each time.
Testing Randomness
How do you know if a random number generator is "good enough"? Several test suites exist:
- TestU01: The gold standard, with the SmallCrush, Crush, and BigCrush batteries
- Dieharder: A comprehensive statistical test suite
- NIST SP 800-22: The US government's statistical test suite for random number generators
- PractRand: Fast and thorough, popular for testing new PRNG designs
Quick Decision Guide
- Games, simulations, art: Use a fast PRNG (Xoshiro, PCG, Mersenne Twister). Seed with system entropy.
- Passwords, tokens, keys: Use a CSPRNG (
crypto.getRandomValues,secretsmodule). Always. - Reproducible experiments: Use a seeded PRNG and record the seed.
- Casual use (picking a random item, coin flip):
Math.random()is fine.
Conclusion
Random numbers are a surprisingly deep topic. The key takeaway: use the right tool for the job. Math.random() is fast and fine for games and UI; crypto.getRandomValues() is essential for anything security-related. And never roll your own cryptographic RNG — use the battle-tested implementations provided by your platform.