Skip to content

Guide

How random is a random number generator?

A computer follows instructions, so how can it pick anything at random? Here is how browsers make random numbers, the two kinds there are, and the small mistakes that quietly make some results more likely than others.

Every online picker, from a dice roller to a wheel spinner, comes down to one question: where does the random number come from? There are two very different answers, and the difference is not about how evenly the numbers are spread. It is about whether anyone could work out the next number before it appears.

Pseudo-random numbers: a formula that looks random

Most programming languages have a quick built-in generator. In JavaScript it is Math.random(). It starts from a hidden number called the seed and runs it through a formula; each result becomes the input for the next one. Chrome, Edge and Node use an algorithm called xorshift128+, which keeps 128 bits of state and only repeats its sequence after 2128 − 1 numbers, according to the team behind Chrome’s JavaScript engine.

The numbers it produces pass statistical tests well, which is all a game or an animation needs. But they are predictable in principle: the whole sequence follows from the state, and the V8 team itself notes that the algorithm is not cryptographically secure. MDN’s documentation is blunt about it: don’t use Math.random() for anything related to security.

Cryptographically secure numbers: unpredictable by design

Browsers also offer crypto.getRandomValues(), the generator used for encryption keys. It is still a generator rather than a physical coin, but a different kind: it is seeded with unpredictable data from the operating system (on Linux and macOS, the same pool behind /dev/urandom) and designed so that even someone who has seen millions of its outputs can’t work out the next one.

GeneratorMath.random()crypto.getRandomValues()
Gives youA decimal from 0 up to (not including) 1Whole numbers filling an array of bytes or 32-bit integers
Seeded fromA value the browser picks onceEntropy collected by the operating system
Can the next value be predicted?In principle, from enough earlier outputsNo, that is what it is designed to prevent
Good forGames, simulations, visual effectsPrize draws, passwords, keys, anything worth cheating at

Does this matter when you pick who washes the dishes? Not really. It matters when someone has a reason to influence the outcome, or when you need to show that nobody could. That is why advertising rules for prize draws ask for a computer process that produces verifiably random results; see how to run a fair giveaway.

The quiet bug: modulo bias

A good source of randomness can still give unfair results if it is turned into a range carelessly. Generators produce raw numbers in a fixed range, and the usual shortcut is to divide and take the remainder (the modulo). Suppose you roll a die from one random byte, which is a number from 0 to 255. There are 256 possible bytes, and 256 = 6 × 42 + 4. Those four left-over values land on the first four faces:

A die rolled from one random byte with the remainder method
FaceBytes that give itChanceFair chance
1, 2, 3, 443 of 25616.80%16.67%
5, 642 of 25616.41%16.67%

The difference looks small, but over 10,000 rolls each of the faces 1 to 4 comes up about 13 times more than it should, and 5 and 6 about 26 times less. With 32-bit numbers the same thing happens on a much smaller scale: 232 is 4,294,967,296, which is 6 × 715,827,882 + 4, so four values are still left over.

The fix is rejection sampling: throw away the left-over values and draw again. For a die rolled from 32-bit numbers, that means ignoring the top 4 of the 4,294,967,296 possible values. A redraw is almost never needed, and every face then has exactly the same number of ways to come up.

Rounding causes a bigger version of the same problem. A common mistake is Math.round(Math.random() * 5) + 1 for a die. Only values below 0.5 round to 0 and only those from 4.5 up round to 5, so 1 and 6 come up 10% of the time each, while 2, 3, 4 and 5 get 20% each. Math.floor(Math.random() * 6) + 1 is the correct form.

Shuffling is easy to get wrong too

Picking several names or making teams means shuffling a list, and shuffles have their own traps. The correct method, the Fisher–Yates shuffle, goes through the list from the end and swaps each item with a random item at or before it. Every possible order is then equally likely.

Two popular shortcuts are not fair:

  • Swapping each item with any item in the list. With three names that gives 3 × 3 × 3 = 27 equally likely paths, but there are 6 possible orders, and 27 doesn’t divide by 6. Three orders come up 5 times in 27 and three only 4 times in 27.
  • Sorting with a random comparison, as in list.sort(() => Math.random() - 0.5). The result depends on the sorting algorithm. When we shuffled A, B, C a million times this way in Node 24 (the same JavaScript engine as Chrome), the list stayed in its original order 37.6% of the time, instead of the fair 16.7%, and B, C, A turned up only 6.2% of the time.

What TickPickr uses

Every random tool on TickPickr runs on the same small piece of code in your browser:

  • Random values come only from crypto.getRandomValues(). Math.random() is never used for a result.
  • Ranges use rejection sampling, so every number has exactly the same chance. Ranges larger than 232 combine two 32-bit values into 53 random bits, enough for any whole number JavaScript can represent exactly.
  • The name picker and its teams use a Fisher–Yates shuffle. The random number generator with No repeats shuffles the whole range for ranges up to 100,000 numbers and draws again on a repeat above that.
  • The wheel spinner chooses the winner before the wheel starts turning; the animation is then steered to stop on it.

Random results look less random than you expect

People often distrust a fair generator because real randomness is lumpier than intuition says. Repeats are a good example. Draw four numbers from 1 to 10, allowing repeats, and the chance that at least two match is 49.6%, close to a coin flip. Draw 12 numbers from 1 to 100 and it is 49.7%. Streaks, clusters and the same name twice in a row are all normal, and a picker that avoided them would be the one that isn’t random.

For how these odds work with dice, including why some totals are much more common than others, read dice probability explained.

Frequently asked questions

Can a computer generate truly random numbers?

Not from a formula alone, because a formula always gives the same output for the same input. Browsers solve this by seeding a secure generator with unpredictable data collected by the operating system, such as timing noise from hardware. The result can’t be predicted by anyone who doesn’t know that seed, which is what matters for a fair draw.

Is Math.random good enough?

For games, animations and simulations, yes: its numbers are spread evenly. It is not meant to be unpredictable, though, so it should not decide anything someone might want to cheat at, such as prize draws, passwords or security codes. Use crypto.getRandomValues for those.

Why did I get the same number twice in a row?

Because each draw is independent. With numbers from 1 to 10, the next draw matches the last one 1 time in 10. A generator that avoided repeats would be less random, not more. If you don’t want repeats, turn on No repeats in the random number generator, which draws without putting numbers back.

Can TickPickr see or change my result?

No. The numbers are drawn by your own browser, on your device, with no request to a server. The result exists only on your screen, so nobody else, including TickPickr, can see it in advance or influence it.

How can I test whether a random generator is fair?

Generate a lot of results and count them. With 6,000 rolls of a fair die you expect about 1,000 of each face, and about 95% of the time each count lands between roughly 943 and 1,057. Faces that are consistently far outside that range over repeated tests point to a bias.