“Just flip a coin” sounds like the end of an argument about fairness. It is closer to the beginning of one. Physical randomisers carry small measurable biases, naive code carries larger ones, and human intuition about randomness is unreliable in ways that are well documented. Here is what actually makes a random choice fair, and when the difference matters.
A coin flip is not exactly 50/50
Persi Diaconis and colleagues at Stanford argued from the physics of a spinning coin that a flip caught in the hand lands the same side up as it started slightly more often than chance, because the coin precesses about its axis rather than rotating cleanly. Their model predicted roughly 51%.
In 2023 a team led by František Bartoš tested this empirically with 350,757 recorded flips and found same-side-up landings in about 50.8% of cases — small, but statistically unambiguous at that sample size.
The practical fix is trivial: do not let anyone see the starting orientation, or let the coin bounce on the ground rather than catching it. Both destroy the bias. For any decision that actually matters, a digital coin flip sidesteps the physics entirely.
Dice are worse
Standard casino dice are machined to tight tolerances with flush, filled pips precisely because ordinary dice are not fair. Cheap dice have drilled pips that remove material unevenly — the 6 face loses six pips’ worth of plastic and the 1 face loses one, shifting the centre of mass and making 6 marginally more likely to land face-up. Rounded corners, moulding seams and hollow interiors all add further bias.
For a board game this is irrelevant. For anything consequential, it is a reason to prefer a digital roll.
Pseudorandom vs truly random
Most software randomness is pseudorandom: a deterministic algorithm that starts from a seed and produces a sequence that passes statistical tests for randomness. Given the same seed, it produces the same sequence every time.
For games, simulations and picking a name from a list, this is completely adequate — the output is statistically well-distributed and nobody can meaningfully predict it.
It is not adequate for security. JavaScript's Math.random() is explicitly not cryptographically secure: its internal state can potentially be reconstructed from observed outputs, which would let an attacker predict future values. Anything involving a password, token, key or session identifier must use a cryptographic source — crypto.getRandomValues() in the browser — which draws entropy from the operating system.
This is why the password generator uses the Web Crypto API while the games use ordinary pseudorandomness. The distinction is about threat model, not quality.
Modulo bias: the subtle bug in naive range code
This one catches experienced developers. The obvious way to get a number from 1 to 10 out of a random byte is:
(randomByte % 10) + 1
A byte holds 0–255, which is 256 values. 256 does not divide evenly by 10. Values 0–5 each occur 26 times across that range, while values 6–9 occur only 25 times. The result is that 1 through 6 come up about 4% more often than 7 through 10.
The correct approach is rejection sampling: discard any value that falls in the uneven tail and draw again. Here you would reject bytes of 250 and above, leaving exactly 250 values that divide evenly by 10. It costs a negligible number of extra draws and removes the bias completely.
With a small range and a large source this bias is tiny. In a lottery, a shuffle used many times, or anything cryptographic, it is not acceptable.
Shuffling correctly
The intuitive shuffle — assign every item a random number and sort by it — is usually fine, but the other intuitive approach is actively broken: passing a random comparator to a sort function.
array.sort(() => Math.random() - 0.5)
This is a well-known bug. Sort algorithms assume a consistent comparator, and an inconsistent one produces distributions that are measurably far from uniform, with the exact skew depending on the engine's sorting implementation.
The correct algorithm is Fisher-Yates: walk the array from the end, and for each position swap it with a randomly chosen position at or before it. Every permutation becomes equally likely, and it runs in linear time. It has been the right answer since 1938 and still is.
Human intuition about randomness is wrong
Two errors show up constantly.
The gambler's fallacy.After five heads in a row, tails is not “due”. A fair coin has no memory; the next flip is 50/50 regardless of history. The same applies to lottery numbers, roulette and dice.
Expecting too few streaks.Asked to write down a “random” sequence of coin flips, people alternate far too much and avoid long runs. Genuinely random sequences are streakier than they feel — in 100 flips, a run of six or seven identical results is entirely ordinary. This is exactly why music streaming services deliberately make their shuffle less random: true shuffling clusters songs by the same artist often enough that users report it as broken.
Running a draw people will trust
For a giveaway or prize draw, statistical fairness is only half the problem. The other half is that participants can verify it was fair. Some practical measures:
- Publish the rules before drawing — the entry list, the closing time, and the method. Deciding the method afterwards invites suspicion regardless of your integrity.
- Make the entry list fixed and visible. A numbered list published in advance means nobody can be added or removed after the fact.
- Draw visibly. A spinning wheel recorded on video is far more persuasive than announcing a name, even though both are equally fair.
- Consider a public seed. For high-stakes draws, some organisers commit in advance to deriving the result from a future public value nobody controls — a specified lottery result or a blockchain block hash. Anyone can then reproduce the outcome independently.
- Decide the duplicate policy up front. If you are drawing several winners, state whether the same person can win twice before you start.
When does any of this matter?
Honestly, for most everyday choices, none of it does. Deciding who does the washing up, picking a restaurant, choosing who goes first — anything at hand is fine, and the bias in a physical coin is far smaller than the bias in whoever proposed the coin flip.
It starts to matter when the stakes rise, when the same mechanism is used repeatedly so small biases compound, when participants have reason to distrust the organiser, or when the output protects something. In that last case the requirement is not merely fairness but unpredictability, and only a cryptographic source provides it.
The short version
- Physical coins and cheap dice carry small real biases.
- Pseudorandom is fine for games; use crypto sources for anything protecting something.
- Watch for modulo bias when mapping random values onto a range.
- Shuffle with Fisher-Yates, never with a random sort comparator.
- Random sequences streak more than intuition expects, and nothing is ever “due”.
- For public draws, verifiability matters as much as fairness.