How random is random?

Last updated: August 12, 2026 · about 7 minutes

Two complaints arrive after every draw. The first is “that's not random, the same person won twice.” The second is “how do I know your website isn't rigged?” The first is a misunderstanding of what randomness looks like. The second is a fair question with a technical answer. This covers both.

Real randomness looks unfair

People expect random results to be evenly spread, and they are not. Independence — the defining property of a random draw — means each draw has no memory of the last, and no mechanism exists to even things out.

So in a hundred coin flips you should expect a run of six or seven of the same face. In a class of thirty, a name picker used daily will call on the same student twice in a row sooner than feels reasonable. With twenty-three people in a room, there is roughly a fifty-fifty chance two share a birthday, which almost nobody believes on first hearing.

The belief that a result is “due” after a run has a name — the gambler's fallacy — and it is worth naming because it also runs in reverse. Organisers sometimes redraw when a repeat winner comes up, feeling that a repeat is unfair. That redraw is the only actual unfairness in the sequence: it makes some outcomes impossible and it is invisible to everyone but the organiser. If you want to prevent repeats, prevent them in the rules, before the draw, by removing previous winners from the list. Then it is a stated constraint rather than a private intervention.

A useful mental correction: fair randomness produces clumps. Perfectly alternating results would be evidence of tampering, not fairness.

Where the numbers come from

Computers do not naturally do random. Almost all “random” numbers come from a pseudo-random number generator: a formula that starts from a seed value and produces a long, statistically shapeless sequence. Same seed, same sequence, every time. That reproducibility is a feature for scientific simulations and a serious weakness for anything where someone might want to predict or reproduce your results.

In a browser, the ordinary function is Math.random(). It is fast, it is fine for animations, and it is what the majority of picker tools use. What it does not promise is unpredictability — browsers may seed it in ways that are not cryptographically secure, and the specification explicitly does not guarantee it is suitable for anything security-related.

The alternative is crypto.getRandomValues(). It draws on entropy the operating system has gathered from genuinely unpredictable physical sources — timing jitter, hardware events, device noise — and it is designed so that seeing past output tells you nothing about future output. It is the function every tool on this site uses for anything that decides a result.

Is that overkill for choosing who does the dishes? Completely. It costs nothing, though, and it means we never have to qualify the answer when someone asks whether a prize draw was predictable.

The bug almost everyone ships: modulo bias

Here is the part that genuinely matters, and it has nothing to do with which generator you chose. Suppose you have a good random number from 0 to 4,294,967,295 — the full range of a 32-bit value — and you need a number from 0 to 2 to pick one of three entrants. The obvious move is to divide and keep the remainder.

Count what that does. There are 4,294,967,296 possible raw values. Divided into three groups by remainder, they do not split evenly: one remainder gets one more value than the others. So one of your three entrants is very slightly more likely to win, purely because of arithmetic.

With three entrants the effect is vanishingly small. But the size of the bias grows with the size of your range relative to the raw range, and it is systematic rather than random — it always favours the low numbers, which in a list means the entries near the top. It is invisible in any small test, and it is present in an enormous amount of shipped code.

The fix is not clever, it is just discipline: identify the values in the uneven tail, throw them away, and draw again. This is called rejection sampling. The loop almost never runs more than once, the cost is unmeasurable, and every outcome ends up with exactly equal probability. That is what our tools do, and it is the specific reason we say the draws are uniform rather than approximately uniform.

Shuffling has the same trap

Putting a list into a random order has an equivalent pitfall. The correct method, Fisher-Yates, walks the list backwards and swaps each item with one chosen from the positions at or before it. Every ordering comes out equally likely.

The broken variant swaps each item with a position chosen from the whole list. It is one word different, it looks more natural, and it produces a measurably uneven distribution of orderings. It has been found in shipped software from very large companies. If you are writing your own picker, this is the detail to get right.

What a website can and cannot prove

Here is the honest limit. We can tell you which generator we call and how we convert its output. We can describe rejection sampling and Fisher-Yates. You can open the browser's developer tools and read our code, because it is plain JavaScript with nothing obscured. What no browser tool can do is prove to a stranger, after the fact, that it behaved as described on a particular occasion.

That is not a gap you should fill with trust in us. It is a gap you fill with your own process: publish rules first, freeze the entry list, record the draw as it happens. Those steps make the question of whether the website cheated largely irrelevant, because you have evidence of the entry list and the moment of selection. Proving your draw was fair is about exactly that, and it does more for your credibility than any claim we could make about our own code.

Related