Random Generators: How They Work and When to Use Them

ยท 13 min read

Random generators are everywhere. Every time you shuffle a playlist, generate a password, run a simulation, or play a video game, a random number generator is working behind the scenes. But have you ever wondered how computers โ€” deterministic machines that follow exact instructions โ€” produce randomness? The answer is more fascinating (and more nuanced) than you might expect.

This guide explores the science and engineering behind random generators. We'll cover the difference between true and pseudo-random numbers, how popular algorithms work, when you need cryptographic-grade randomness, and practical applications that affect your daily life. Whether you're a developer choosing the right random function, a student learning about probability, or simply curious about how things work, this guide has you covered.

What Is Randomness? A Deeper Look

Randomness seems intuitive โ€” it's unpredictability, chaos, the absence of pattern. But defining randomness precisely is surprisingly difficult, and mathematicians have debated it for centuries.

In the strictest sense, a sequence is truly random if no algorithm can predict the next value better than guessing, even with complete knowledge of all previous values. This is called Kolmogorov randomness โ€” a sequence is random if it cannot be compressed to a shorter description. The digits of pi, for instance, pass every statistical test for randomness, yet they're completely deterministic (you can calculate any digit with enough computation).

For practical purposes, we care about three properties of randomness:

Different applications require different levels of these properties. A dice-rolling game needs uniformity and independence, but not necessarily unpredictability. A password generator needs all three. Understanding what kind of randomness your application requires is the first step to choosing the right generator.

True Random vs. Pseudo-Random: The Fundamental Divide

All random generators fall into two categories, and the distinction matters enormously for both correctness and security.

True Random Number Generators (TRNGs)

True random generators derive randomness from physical phenomena that are fundamentally unpredictable:

The key property of TRNGs is that their output is non-reproducible. Even with identical equipment and conditions, you'll get different sequences every time. This is essential for cryptographic applications where reproducibility would be a fatal flaw.

Pseudo-Random Number Generators (PRNGs)

PRNGs are algorithms โ€” deterministic mathematical formulas that produce sequences of numbers that appear random but are entirely predictable given the initial state (called the seed). Give a PRNG the same seed, and it produces the exact same sequence every time.

This might sound like a weakness, but it's actually a feature for many applications:

The challenge is designing PRNGs whose output is statistically indistinguishable from true randomness โ€” passing all known statistical tests for uniformity, independence, and lack of pattern.

๐ŸŽฒ Try our generators

Random Number Generator โ†’ Password Generator โ†’

How Pseudo-Random Number Generators (PRNGs) Work

At their core, PRNGs maintain an internal state that they transform with each call, producing an output and updating the state for next time. The quality of a PRNG depends on how well its transformation avoids patterns and correlations.

Linear Congruential Generator (LCG)

The simplest and oldest PRNG family, LCGs use the formula:

state = (a ร— state + c) mod m
output = state

Where a (multiplier), c (increment), and m (modulus) are carefully chosen constants. For example, the classic MINSTD generator uses a = 16807, c = 0, m = 2ยณยน - 1. LCGs are blazing fast (a multiply and a modulo) but have well-known weaknesses: sequential values show patterns when plotted in higher dimensions, and low-order bits cycle with short periods. Most modern applications have moved beyond LCGs.

Mersenne Twister (MT19937)

The Mersenne Twister has been the default PRNG in many languages and systems since its introduction in 1997. It maintains a state of 624 32-bit integers and has a period of 2ยนโนโนยณโท - 1 (a Mersenne prime, hence the name). That period is astronomically long โ€” far more than the number of atoms in the observable universe.

The algorithm works by:

  1. Initializing 624 state values from a seed
  2. For each random number, extracting and "tempering" a state value through bit shifts and XOR operations
  3. Periodically regenerating the entire state array using a twist transformation

Mersenne Twister passes most statistical tests and is excellent for simulations, games, and general-purpose use. However, it is not cryptographically secure โ€” observing 624 outputs allows reconstructing the full internal state and predicting all future values.

Xoshiro256** and Modern PRNGs

Newer PRNGs like xoshiro256** (used in many modern languages) and PCG (Permuted Congruential Generator) address the shortcomings of older generators. They offer:

JavaScript's Math.random()

When you call Math.random() in JavaScript, modern engines (V8, SpiderMonkey, JavaScriptCore) use xorshift128+, a fast PRNG with good statistical properties. It produces a floating-point number between 0 (inclusive) and 1 (exclusive). While perfectly fine for games, shuffles, and random selection, it should never be used for security-sensitive purposes.

// Basic random number between min and max (inclusive)
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Random element from an array
function randomChoice(array) {
  return array[Math.floor(Math.random() * array.length)];
}

// Shuffle an array (Fisher-Yates algorithm)
function shuffle(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

Cryptographic Randomness: When Security Matters

For security applications โ€” passwords, encryption keys, session tokens, nonces โ€” regular PRNGs are dangerously inadequate. An attacker who can predict your random numbers can compromise your entire security model.

What Makes a CSPRNG Different?

A Cryptographically Secure Pseudo-Random Number Generator (CSPRNG) adds a critical property: forward and backward secrecy. Even if an attacker discovers the current internal state, they cannot determine previous outputs (backward secrecy). And predicting future outputs from past outputs is computationally infeasible without knowing the state.

CSPRNGs achieve this through:

Common CSPRNGs

Using Cryptographic Randomness in Practice

In the browser, the Web Crypto API provides cryptographic-grade randomness:

// Generate a cryptographically secure random integer
function secureRandomInt(min, max) {
  const range = max - min + 1;
  const bytesNeeded = Math.ceil(Math.log2(range) / 8);
  const maxValid = Math.floor(256 ** bytesNeeded / range) * range - 1;

  let value;
  do {
    const array = new Uint8Array(bytesNeeded);
    crypto.getRandomValues(array);
    value = array.reduce((acc, byte, i) => acc + byte * (256 ** i), 0);
  } while (value > maxValid); // Reject biased values

  return min + (value % range);
}

// Generate a secure random password
function generatePassword(length = 16) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
  const array = new Uint32Array(length);
  crypto.getRandomValues(array);
  return Array.from(array, x => chars[x % chars.length]).join('');
}

Try generating secure passwords with our Password Generator, which uses the Web Crypto API for cryptographic-grade randomness.

Entropy: The Fuel of Randomness

Entropy, in the context of randomness, measures the amount of genuine unpredictability in a system. It's measured in bits โ€” one bit of entropy means one binary choice that an attacker cannot predict.

Where Does Entropy Come From?

Operating systems continuously collect entropy from multiple sources:

The Entropy Pool

Operating systems maintain an entropy pool โ€” a buffer of collected randomness that's continuously stirred and mixed using cryptographic functions. On Linux, the kernel collects entropy from interrupts and feeds it into a ChaCha20-based CSPRNG. On macOS and iOS, the Security framework provides a unified interface through SecRandomCopyBytes.

A common concern is entropy exhaustion โ€” running out of collected randomness. On modern systems with hardware RNGs, this is rarely an issue. The historic Linux distinction between /dev/random (blocking, "true" entropy) and /dev/urandom (non-blocking, CSPRNG-stretched) has been largely resolved โ€” both are now considered equally secure for cryptographic purposes.

Measuring Entropy

Shannon entropy quantifies the information content of a distribution:

H = -ฮฃ p(x) ร— logโ‚‚(p(x))

For a fair 6-sided die, each outcome has probability 1/6, giving H = logโ‚‚(6) โ‰ˆ 2.585 bits per roll. A fair coin gives exactly 1 bit. An unfair coin that lands heads 90% of the time gives only 0.469 bits โ€” its outcomes are partially predictable, so it contributes less entropy.

Password strength is often expressed in bits of entropy. A random 12-character password using 95 printable ASCII characters has logโ‚‚(95ยนยฒ) โ‰ˆ 78.8 bits of entropy โ€” enough to resist brute-force attacks for decades.

Random Distributions Explained

Not all randomness is equal. Different applications need random numbers that follow different probability distributions. Most generators produce uniform random numbers, which can then be transformed into other distributions.

Uniform Distribution

Every value in the range is equally likely. This is what Math.random() and most basic generators provide. Rolling a fair die, selecting a random card, or generating a random number between 1 and 100 all use uniform distributions.

Normal (Gaussian) Distribution

The bell curve โ€” values cluster around a mean with decreasing probability at the extremes. Natural phenomena like human heights, measurement errors, and test scores approximately follow this distribution. The Box-Muller transform converts uniform random numbers to normal distribution:

function randomNormal(mean = 0, stddev = 1) {
  const u1 = Math.random();
  const u2 = Math.random();
  const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
  return mean + z * stddev;
}

Exponential Distribution

Models the time between independent events โ€” like the interval between customer arrivals, radioactive decay events, or server requests. Events are memoryless: the probability of the next event doesn't depend on time elapsed.

Poisson Distribution

Counts the number of events in a fixed interval โ€” emails per hour, defects per batch, or accidents per year. It's the discrete counterpart to the exponential distribution.

Weighted/Non-Uniform Selection

When outcomes shouldn't be equally likely โ€” like a gacha game with different rarity tiers or a weighted random selection โ€” you need weighted random sampling:

function weightedRandom(items, weights) {
  const totalWeight = weights.reduce((sum, w) => sum + w, 0);
  let random = Math.random() * totalWeight;
  for (let i = 0; i < items.length; i++) {
    random -= weights[i];
    if (random <= 0) return items[i];
  }
  return items[items.length - 1];
}

// Example: loot drop with 70% common, 25% rare, 5% legendary
weightedRandom(['common', 'rare', 'legendary'], [70, 25, 5]);

Practical Use Cases for Random Generators

Random generators power more of our digital lives than most people realize. Here are the major categories:

๐Ÿ” Security & Cryptography

๐ŸŽฎ Gaming

๐Ÿ”ฌ Science & Simulation

๐Ÿ“Š Data & Testing

๐ŸŽจ Creative & Everyday

Common Mistakes with Random Generators

Even experienced developers make these errors with randomness. Avoid them:

1. Using Math.random() for Security

This is the most dangerous mistake. Math.random() is predictable โ€” an attacker who observes enough outputs can determine the internal state and predict all future values. For passwords, tokens, keys, or any security-sensitive value, always use crypto.getRandomValues() or equivalent CSPRNGs.

2. Modulo Bias

When converting a random number to a specific range using the modulo operator, certain values become slightly more likely than others. For example, if your PRNG produces values 0-255 and you want 0-99: values 0-55 are each mappable from 3 source values, while 56-99 map from only 2. The fix: reject values above the largest even multiple of your range (rejection sampling).

3. Seeding with Time

Using the current timestamp as a PRNG seed is common but dangerous for security applications. An attacker who knows approximately when your program started can try all plausible seeds (often just seconds or minutes of timestamps) to reproduce your "random" sequence.

4. Assuming Uniform Means Fair

A uniform PRNG gives each number equal probability, but humans perceive randomness differently. True random sequences often contain clusters and streaks that feel non-random. If you need perceived fairness (like music shuffle), you may need to add constraints (e.g., no artist plays twice in a row) on top of randomness.

5. Reusing Seeds Across Security Contexts

Each security context (each user session, each encryption operation) should use independently generated randomness. Reusing or deriving seeds from shared sources creates correlations that attackers can exploit.

Random Generators in the Browser

Modern browsers provide two levels of random number generation, each suited to different purposes:

Math.random() โ€” For General Use

Fast, convenient, and sufficient for non-security uses:

// Random float between 0 and 1
Math.random()  // e.g., 0.7382916438291

// Random integer between 1 and 6 (inclusive)
Math.floor(Math.random() * 6) + 1

// Random hex color
'#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')

crypto.getRandomValues() โ€” For Security

Cryptographically secure, slightly slower, essential for sensitive operations:

// Generate 16 random bytes
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);

// Generate a random UUID (v4)
crypto.randomUUID()  // e.g., "3b241101-e2bb-4d7a-8702-9e3f8c8e4f79"

// Secure shuffle
function secureShuffled(array) {
  const result = [...array];
  const randoms = new Uint32Array(result.length);
  crypto.getRandomValues(randoms);
  for (let i = result.length - 1; i > 0; i--) {
    const j = randoms[i] % (i + 1);
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}

Which Should You Use?

Use Case Generator
Games, animations, UI effectsMath.random()
Random selection (picker, dice)Math.random()
Passwords, PINscrypto.getRandomValues()
Session tokens, API keyscrypto.getRandomValues()
UUIDscrypto.randomUUID()
Encryption keys, noncescrypto.getRandomValues()

Frequently Asked Questions

Can computers generate truly random numbers?

Standard computer algorithms cannot generate truly random numbers โ€” they produce pseudo-random sequences that are deterministic given a seed. However, modern computers can harvest true randomness from physical sources like thermal noise, hardware timing jitter, and dedicated hardware RNG circuits (Intel RDRAND). Operating systems collect this physical entropy and use it to seed cryptographic generators, providing effectively unpredictable output.

Is Math.random() safe for generating passwords?

No. Math.random() uses a predictable algorithm (xorshift128+ in most browsers) that an attacker can reverse-engineer from observed outputs. For passwords, always use the Web Crypto API: crypto.getRandomValues(). This provides cryptographically secure randomness sourced from the operating system's entropy pool. Our Password Generator uses this secure approach.

What is entropy in the context of random number generation?

Entropy measures the amount of genuine unpredictability in a system, expressed in bits. One bit of entropy represents one unpredictable binary choice. For password strength, entropy indicates how many guesses an attacker would need: a 128-bit password requires 2ยนยฒโธ (about 3.4 ร— 10ยณโธ) guesses to brute-force. Operating systems collect entropy from hardware sources like mouse movements, keyboard timing, and dedicated RNG circuits.

What is the Mersenne Twister and why is it popular?

The Mersenne Twister (MT19937) is a pseudo-random number generator introduced in 1997 with a period of 2ยนโนโนยณโท - 1. It's popular because of its excellent statistical properties, long period, and fast execution. It has been the default PRNG in Python, Ruby, R, PHP, and many other languages. However, it's not cryptographically secure โ€” observing 624 consecutive outputs reveals the internal state and enables predicting all future values.

How do random number generators work in games?

Games typically use seeded PRNGs for reproducibility. In procedural generation (Minecraft, No Man's Sky), a single seed generates an entire consistent world. For gameplay mechanics like loot drops and critical hits, games use weighted random distributions where different outcomes have different probabilities. Many games also implement "pity systems" that modify randomness to guarantee rare outcomes after a certain number of attempts, preventing frustrating losing streaks.

What is the difference between /dev/random and /dev/urandom on Linux?

Historically, /dev/random blocked when the system's entropy pool was estimated to be depleted, while /dev/urandom continued generating numbers using a CSPRNG. Since Linux kernel 5.6, both behave identically after initial seeding โ€” they both use the same ChaCha20-based CSPRNG and are equally secure for all practical purposes. The old advice to prefer /dev/random for "stronger" randomness is outdated.

Conclusion

Random generators are one of computing's most fundamental building blocks, touching everything from security to science to entertainment. The key takeaway: match your generator to your use case. Use fast PRNGs like Math.random() for games and simulations. Use CSPRNGs like crypto.getRandomValues() for anything security-related. And remember โ€” what humans perceive as "random" and what's mathematically random are often surprisingly different things.

Ready to put randomness to work? Try our Random Number Generator, create unbreakable passwords with our Password Generator, or generate unique identifiers with our UUID Generator.

Related Tools

Random Number Generator Password Generator UUID Generator