← Back to Blog

How Random Number Generators Work: True vs Pseudo-Random Numbers Explained

By UtilDaily8 min read

When you roll a die, the outcome is genuinely unpredictable. Slight variations in how you throw it, air resistance, table surface — hundreds of variables conspire to land on any face with roughly equal probability. Computers have a problem: they are entirely deterministic. Give a computer the same inputs and the same starting state, and it will always produce the same output. So how do computers generate "random" numbers at all?

The answer depends on which kind of randomness you need — and the difference between pseudo-random, true-random, and cryptographically secure numbers is far more consequential than most developers realize.

What Is Randomness, and Why Is It Hard for Computers?

A sequence of numbers is considered random if it has no pattern, no predictability, and each value is statistically independent from the last. In information theory, this is called entropy — a measure of unpredictability. The problem is that software running on a CPU follows strict, logical rules. Every instruction produces a deterministic result. True randomness requires an external, physical source of entropy.

This is not just a philosophical curiosity. If a random number generator is predictable, an attacker can figure out what numbers it will produce next — which breaks encryption, authentication tokens, session IDs, and more. This is why the type of RNG you use matters enormously depending on your use case.

Pseudo-Random Number Generators (PRNGs): Fake Randomness That Fools Most People

A pseudo-random number generator (PRNG) is an algorithm that takes an initial value called a seed and produces a long sequence of numbers that appears random but is entirely deterministic. If you know the seed, you can reproduce the entire sequence.

The most widely used PRNG algorithm is the Mersenne Twister, which has been the default in Python, Ruby, R, and PHP for decades. It passes most statistical tests for randomness — the numbers are well-distributed and show no obvious patterns in small samples. But it has a fatal flaw: given 624 consecutive outputs, an attacker can reconstruct the internal state and predict every future number it will ever produce.

Common uses for PRNGs include:

  • Games and simulations — shuffling a deck of cards, procedural world generation, dice rolls in casual games
  • Statistical sampling — random sampling in surveys, A/B test assignment
  • Monte Carlo simulations — scientific modeling that needs millions of "random" values fast
  • Reproducible research — setting a seed so an experiment can be replicated exactly

For all of these uses, PRNGs are fast, efficient, and perfectly adequate — as long as security is not a concern.

True Random Number Generators (TRNGs): Hardware Entropy

A true random number generator (TRNG) harvests entropy from physical phenomena that are genuinely unpredictable at the quantum level. Common sources include:

  • Thermal noise — random fluctuations in electrical current through a resistor
  • Radioactive decay — the timing of particles emitted by a radioactive source is fundamentally unpredictable
  • Photon arrival times — used in quantum random number generators
  • Atmospheric noise — the randomness in radio static, famously used by Random.org
  • Mouse movements and keystrokes — your computer's operating system collects entropy from hardware events

Modern operating systems expose this hardware entropy pool via special interfaces: /dev/random on Linux, the CryptGenRandom API on Windows. These are slow — they can only produce randomness as fast as physical events occur — but they are the gold standard for seeding cryptographic systems.

Cryptographically Secure PRNGs (CSPRNGs): The Best of Both Worlds

In practice, most security-critical software uses a cryptographically secure PRNG (CSPRNG). The idea is elegant: seed a PRNG with a small amount of true randomness from hardware entropy, then use a mathematically strong algorithm to stretch it into a long sequence that is computationally infeasible to predict — even if you know the algorithm.

The key property of a CSPRNG is forward secrecy: even if an attacker somehow captures the current internal state, they cannot determine any past outputs, and recovering future outputs requires solving problems equivalent to breaking modern encryption.

In browsers, the Web Crypto API exposes a CSPRNG through crypto.getRandomValues(). This is the correct way to generate random numbers in JavaScript for anything where security matters — generating tokens, UUIDs, passwords, or cryptographic keys. Our random number generator uses crypto.getRandomValues() exclusively, which means the numbers it produces are suitable for security-sensitive applications.

The Birthday Paradox: Why True Randomness Surprises Us

One of the most counterintuitive facts about randomness is the birthday paradox. In a room of just 23 people, there is a 50% chance that two of them share a birthday. With 70 people, the probability exceeds 99.9%. This seems wrong — there are 365 days, and we only have 23 people — but the math checks out.

The birthday paradox has serious implications for random number generators. If you're generating session tokens or UUIDs and your RNG is weak, the probability of a collision (two users getting the same token) grows much faster than intuition suggests. This is why UUID v4, which uses 122 bits of randomness, is so collision-resistant — the birthday paradox still applies, but you would need to generate approximately 2.7 quintillion UUIDs before having a 50% chance of a single collision. Our UUID generator uses exactly this approach.

Random Numbers in Different Programming Languages

Here is how to generate random numbers correctly across common languages:

Python

For simulations and games, use the random module. For cryptography, use secrets:

import random
import secrets

# Not cryptographically secure (fine for games/simulations)
print(random.randint(1, 100))

# Cryptographically secure (use for tokens, passwords)
print(secrets.randbelow(100) + 1)
print(secrets.token_hex(16))  # Random hex string

JavaScript

Never use Math.random() for security. Use crypto.getRandomValues():

// Not secure - DO NOT use for tokens
Math.random() * 100

// Cryptographically secure
const array = new Uint32Array(1);
crypto.getRandomValues(array);
const number = array[0] % 100 + 1;

Java

Use SecureRandom instead of Random for anything security-related:

import java.security.SecureRandom;

SecureRandom sr = new SecureRandom();
int randomNumber = sr.nextInt(100) + 1; // 1 to 100

Online Random Number Generators: When to Use Them

Browser-based random number generators like ours are ideal when you need quick, unbiased random values without writing code. Common use cases include:

  • Picking a lottery number or raffle winner
  • Generating a random sample from a dataset
  • Assigning random groups in a classroom activity
  • Making a decision when you genuinely cannot choose ("should I order pizza or pasta?")
  • Testing random inputs during software development

For generating random strings, tokens, or identifiers, our random string generator gives you control over length, character sets, and output format — all using secure randomness.

How Our Random Number Generator Works

Our random number generator runs entirely in your browser using the Web Crypto API. When you request a number between 1 and 100, the tool calls crypto.getRandomValues() to fill a typed array with hardware-entropy-backed random bytes, then applies modular arithmetic to map those bytes into your requested range — with a rejection sampling technique to eliminate modulo bias.

No data is sent to any server. Every random number is generated locally on your device, making it both private and cryptographically strong.

Frequently Asked Questions

Is Math.random() safe to use in JavaScript?

Not for security purposes. Math.random() is a PRNG (typically xorshift128+ in V8) that is fast and statistically decent, but it is not cryptographically secure. Never use it to generate passwords, tokens, or session IDs. For security-sensitive applications, always use crypto.getRandomValues().

What is a seed in a random number generator?

A seed is the initial input value that determines the entire output sequence of a PRNG. Two PRNGs with the same seed will produce identical sequences. Seeds are useful in reproducible research and game development (so a world can be regenerated identically), but they make PRNGs unsuitable for cryptography — if an attacker learns the seed, they know all outputs.

Can any computer generate truly random numbers?

Modern computers can harvest true randomness from hardware entropy sources — thermal noise in circuits, timing variations in disk I/O, mouse movements, and similar physical events. Operating systems collect this entropy and expose it via APIs like /dev/urandom (Linux) and crypto.getRandomValues() (browsers). So yes, with the right APIs, computers can generate cryptographically strong random numbers.

Why do random number generators sometimes repeat numbers?

Repetition is actually a property of true randomness. If you roll a die six times, getting the same number twice in a row is expected to happen about 20% of the time. If a random number generator never repeated numbers in a short sequence, that would be a sign of bias. What you want is that the frequency of each value approaches equal probability over a large number of trials — not that values never repeat.

What is modulo bias and why does it matter?

Modulo bias occurs when you map a large range of random values onto a smaller range using the modulo operator (%), and the larger range is not evenly divisible by the smaller range. Some output values become slightly more likely than others. Quality random number generators use rejection sampling — discarding values that would cause bias and drawing again — to ensure perfectly uniform distribution.

Related Tools