How Online Random Number Generators Work: PRNG vs True RNG

Most online random number generators, including the one on Pick4Us, use a pseudo-random number generator (PRNG): a fixed algorithm that starts from a hidden seed and produces numbers that look random and pass statistical tests. Cryptographically secure generators add unpredictability, and hardware generators measure physical noise. For games, classroom picks and everyday choices, a good PRNG is plenty; for passwords or legally regulated draws, it isn’t.

Three kinds of random number generator

TypeWhere the randomness comes fromTypical uses
Pseudo-random (PRNG)A formula applied over and over to an internal state, starting from a seedGames, simulations, everyday picks (Math.random())
Cryptographically secure PRNG (CSPRNG)An algorithm designed so past outputs don’t reveal future ones, seeded with entropy collected by the operating systemPasswords, keys, security tokens (crypto.getRandomValues())
Hardware or “true” RNGMeasurements of a physical process, such as electronic noiseSeeding CSPRNGs, specialised equipment

Seeds and periods in plain language

A CSPRNG closes that gap: even with many outputs in hand, guessing the next bit should be no better than chance. A hardware random number generator measures a physical process, but raw noise is slow and needs processing, so operating systems usually feed it into a CSPRNG as seed material rather than reading it for every request.

Math.random() vs crypto.getRandomValues()

Math.random() returns a decimal from 0 up to but not including 1, approximately uniformly distributed. The ECMAScript specification leaves the algorithm to each engine, and, as MDN notes, the engine also picks the seed, which you cannot choose or reset.

In practice the major engines converged on xorshift128+ in 2015–2016. V8, the engine in Chrome and Node.js, adopted it in version 4.9.41, which shipped with Chrome 49, replacing an older generator (MWC1616) that failed many statistical tests. Firefox’s SpiderMonkey and Safari’s JavaScriptCore made the same switch around that time. Engines remain free to change this; the specification guarantees no particular algorithm.

crypto.getRandomValues() fills an array of integers with cryptographically strong random values. As MDN explains, browsers don’t read a hardware source on every call; for performance they use a CSPRNG seeded with enough entropy. One call can fill at most 65,536 bytes. It is slower than Math.random(), but not noticeably at human scale.

One trap when turning random bytes into a range: taking the remainder introduces a small bias. A byte has 256 possible values, and 256 = 6 × 42 + 4, so with “byte % 6”, 43 of the 256 byte values lead to each of 0, 1, 2 and 3, but only 42 lead to each of 4 and 5. Careful code discards the few leftover values and draws again.

When Math.random() is fine, and when it isn’t

Math.random() suits:

Not suitable for:

  • Passwords, PINs, verification codes, API keys, session or password-reset tokens. Use crypto.getRandomValues() or a password manager.
  • Legally regulated draws, such as official prize draws or admissions and housing lotteries. These often have legal rules on method, witnesses and records; check what applies where you are. A browser tool is not an audited draw.
  • Anything where someone could gain by predicting the results.

Pick4Us uses Math.random() for all its tools, which suits quick everyday picks, and the site can’t preset outcomes. It doesn’t use crypto.getRandomValues() and doesn’t claim “true randomness”.

Getting numbers without repeats

With repeats allowed, duplicates come sooner than intuition suggests. Draw 10 numbers from 1–100 and the chance of at least one duplicate is about 37%: multiply the chances that each new number misses the earlier ones, 100/100 × 99/100 × … × 91/100 ≈ 0.628, then subtract from 1. It’s the birthday problem in another form.

In the Random Number tool:

How do you pick 5 unique numbers from a trillion without listing a trillion numbers? The tool uses Floyd’s sampling algorithm, published by Jon Bentley and Bob Floyd in a 1987 “Programming Pearls” column in Communications of the ACM. To choose k numbers out of n, it takes k steps. Each step picks a random number from 0 up to a limit that starts at n − k and rises by one per step; if that number is already taken, it takes the limit itself. Every set of k numbers is equally likely, and the work depends on k, not on the size of the range. The chosen numbers are then shuffled so their order is random too.

For names rather than numbers, the Spin Wheel does the same job with its Draw without replacement mode, which removes each pick before the next spin. The wheel also accepts whole-number weights from 1 to 100; each option’s chance is its weight divided by the total weight of the options still on the wheel.

Inclusive ranges and the off-by-one trap

Pick4Us ranges include both ends: with Min 1 and Max 6, both 1 and 6 can come up. The number of possible values is max − min + 1, so 1–100 has 100 values while 0–100 has 101.

In your own code, the standard inclusive formula (MDN’s getRandomIntInclusive example) is Math.floor(Math.random() * (max − min + 1)) + min. Two mistakes are common:

Simple ways to sanity-check fairness

Output alone can’t prove a generator is random, but it can reveal obvious problems.

  1. Collect plenty of draws. Turn Unique off (otherwise a value can appear only once per generation), generate up to 500 numbers at a time, copy them into a spreadsheet and repeat.
  2. Work out the expected count: draws ÷ number of possible values.
  3. Compare with the normal spread. For a fair generator, one value’s count has a standard deviation of √(draws × p × (1 − p)), where p = 1 ÷ number of possible values. Counts within about two standard deviations of the expected count are normal, and with many values, one or two outside that band is normal too.
DrawsRangeExpected per valueNormal range (about ±2 SD)
601–610about 4–16
6001–6100about 82–118
1,0001–10100about 81–119
1,0001–2500about 468–532

For one summary number, use the chi-square statistic: add up (observed − expected)² ÷ expected over all values. With 6 possible values, a fair generator gives a total above 11.07 only 5% of the time; with 10 values, the 5% threshold is 16.92. One result above it proves nothing, since about 1 test in 20 crosses it by chance; repeated failures are worth investigating.

Small samples mislead: in 60 rolls of a die, one face turning up only 5 or as many as 15 times is ordinary. Our article on coin flip odds shows how long streaks appear in perfectly fair sequences.

Takeaway: Most online random number generators are pseudo-random. Math.random() is fine for games, classrooms and everyday picks; passwords, tokens and regulated draws need a cryptographically secure source and a proper procedure. Use Unique or the number pool when repeats matter, remember that ranges include both ends, and judge fairness from hundreds of draws, not a handful.

Try the tools from this article

Random Number · Spin Wheel

Related articles

← Back to Blog