How Random Number Generators Actually Work (PRNG vs CSPRNG, Explained Simply)

Computers are deterministic machines: give one the same input twice and it produces the same output twice. So where does randomness come from? Here's the whole story — seeds, entropy pools, and why some "random" numbers are more random than others — without the math degree.

By the FairPick team · Published June 11, 2026

What "Random" Actually Means

When people say a sequence of numbers is random, they usually mean three separate things at once, and it helps to pull them apart:

Uniformity

Every possible value comes up equally often in the long run. A die that rolls six 30% of the time fails this test, even if you can't predict any individual roll.

Independence

Knowing the previous results tells you nothing about the next one. A sequence like 1, 2, 3, 4, 5, 6 is perfectly uniform but completely dependent.

Unpredictability

Even someone who has watched thousands of outputs — and knows exactly how the generator works — cannot guess the next one better than chance.

Most everyday generators deliver the first two properties easily. The third one is the hard part, and it's the property that separates a casual randomizer from one you'd trust with money on the line.

The Problem: Computers Can't Improvise

A CPU executes instructions exactly. There is no circuit inside a processor labelled "surprise me." Any number a program computes is, by definition, the predictable result of its inputs. This is why every software random number generator is really one of two things: an algorithm that simulates randomness (a pseudorandom number generator, or PRNG), or a pipeline that harvests randomness from the physical world and cleans it up (the approach behind cryptographically secure generators).

Pseudorandom Generators: Stretching a Seed

A PRNG starts from a seed — one initial number — and applies a scrambling function over and over. Each output becomes input to the next round. A well-designed PRNG produces output that passes every statistical test for uniformity and independence, and it can produce billions of values per second.

The catch is in the word seed. The entire infinite-looking sequence is fully determined by that one starting value. Seed a PRNG with the same number twice and you get the identical "random" sequence twice. This is occasionally a feature — game developers use fixed seeds so a procedurally generated world is the same for every player — but it means a PRNG is only as unpredictable as its seed, and its internal state can sometimes be reconstructed by observing enough outputs.

JavaScript's Math.random() is a PRNG. Modern browsers implement it with an algorithm called xorshift128+, which is fast and statistically excellent. But it was never designed to resist a motivated adversary: researchers have shown that after observing a handful of consecutive outputs, the internal state can be recovered and every future "random" value predicted exactly.

Cryptographically Secure Generators: Harvesting Entropy

The unpredictable approach starts outside the algorithm. Your operating system continuously collects entropy — genuine physical unpredictability — from sources like the microsecond-level timing of your keystrokes and mouse movements, network packet arrival jitter, storage controller interrupts, and dedicated hardware generators built into modern CPUs (Intel and AMD chips have an instruction, RDRAND, that samples thermal noise in the silicon).

All of this gets mixed into an entropy pool, then fed through a cryptographically secure pseudorandom number generator (CSPRNG). The CSPRNG stretches that physical entropy into as many output bytes as programs ask for, with a guarantee the casual PRNG never makes: even an observer who has captured previous outputs and knows the full algorithm cannot predict the next output or reconstruct earlier ones.

In the browser, this pipeline is exposed as crypto.getRandomValues() — the same source used to generate the encryption keys protecting your banking session. It's the source FairPick's number generator and all our picking tools use.

The Subtle Bug: Modulo Bias

Having good random bytes is only half the job. The other half is mapping them onto your actual range — say, picking a winner among 7 entries — without distorting the odds. The naïve approach is the remainder operator: generate a number between 0 and 255, then take value % 7.

Here's the problem: 256 doesn't divide evenly by 7. The values 0–255 map onto the results 0–6 in 36 complete cycles (252 values), with 4 values left over — and those leftovers all land on results 0 through 3. So results 0–3 each have 37 ways to occur while results 4–6 have only 36. Entry number one is now slightly more likely to win than entry number seven. The skew is small, but it is real, measurable, and completely avoidable.

The standard fix is rejection sampling: compute the largest multiple of your range that fits (here, 252), and if the raw random value lands in the uneven tail (252–255), throw it away and draw again. The retry costs nanoseconds and the result is exactly uniform. Any randomizer that handles arbitrary list lengths correctly has to do this, and it's a good question to ask of any tool whose fairness you care about.

What This Means for Everyday Random Picks

Casual decisions

Choosing tonight's takeout or who goes first in a board game? Any generator is fine. The statistical quality of even Math.random() vastly exceeds what these decisions need.

Classroom picks

Predictability isn't a realistic threat, but uniformity is the point — every student should have genuinely equal odds. A correctly implemented generator, free of modulo bias, delivers that.

Giveaways and raffles

Once a prize has value, unpredictability matters. Use a tool built on the CSPRNG (crypto.getRandomValues) so that no one — including the host — could predict or steer the outcome.

Anything with money at stake

Real lotteries and gambling are regulated for a reason and use audited hardware generators. No browser tool, ours included, is a substitute for a certified draw system.

One last practical note: a random shuffle (used for splitting people into teams) has its own classic pitfall. The correct algorithm, Fisher-Yates, walks the list once and swaps each item with a uniformly chosen earlier position. Intuitive alternatives — like sorting by a random key or swapping random pairs a few times — produce measurably uneven orderings. It's the shuffle our team generator uses, and another detail worth checking in any tool you rely on.

Questions

Randomness FAQs.

Can a computer generate truly random numbers?

Not by computation alone. True unpredictability has to come from the physical world — timing jitter, electrical noise, hardware generators — which the operating system collects and feeds into a cryptographically secure generator. The computation stretches the physical randomness; it doesn't create it.

Is Math.random() "broken"?

No — it's excellent at what it's for: fast, statistically uniform numbers for games, simulations, and visual effects. It's simply not designed to be unpredictable to an adversary, which is a different and harder requirement.

Why do lotteries still use physical ball machines?

Mostly for visible fairness. A transparent tumbling drum can be watched and audited by anyone in the room, with no trust in software required. Statistically, a certified hardware RNG is at least as fair — but it isn't as convincing on television.

How can I check whether a randomizer is biased?

Run it a lot and count. Put ten entries in, pick (with replacement) a few hundred times, and tally the results — each entry should converge toward 10% of the picks, with the spread shrinking as you add trials. Big persistent deviations on a large sample suggest bias; small fluctuations are exactly what real randomness looks like.

See a CSPRNG in Action

Our number generator draws every value from crypto.getRandomValues() with proper rejection sampling. Free, no signup.

🎲 Open Number Generator →

Related reading: Why the Same Name Keeps Winning · A Short History of Fair Random Selection