Skip to content
WGX

Random Number Generator

Draw a number, or several without repeats, from your browser’s cryptographic randomness rather than a source anyone can anticipate.

Quick presets

Coin flip: 1 is heads, 2 is tails — the number itself is what gets drawn.

Options

A number appears here as soon as the page loads.

The real problem with Math.random is not the one you have read about

Almost every random number generator on the web is built on Math.random, and almost every page explaining why that is a problem says the same thing: that it is biased, that some numbers come up more often than others. That claim is, for practical purposes, false — and repeating it gets in the way of the real objection.

The usual implementation is Math.floor(Math.random() * n). It does distribute unevenly, because the generator produces one of roughly 253 values and those do not divide evenly into a range. Counted exactly for a range of 100, the excess is about one part in 1014, and it grows only in proportion to the size of the range. At that size you could draw a number every nanosecond since the beginning of the universe and still not have the evidence to detect it. Nobody has ever lost anything to it.

What Math.random actually is, is predictable. It is a deterministic generator with a small internal state. Given a short run of its output, that state can be recovered — and from the state, every value it will produce next, and every value it already produced. It passes the statistical tests you would think to run, and it fails the only one that matters when the number decides something in the open: nobody watching should be able to work out what comes next. This page draws from crypto.getRandomValues instead, and never falls back — if that source were missing, it says so rather than quietly substituting the weaker one, because the two produce output you cannot tell apart.

Where modulo bias is real, and why this page has to handle it

Dismissing the bias claim above does not make the problem disappear; it moves it. A cryptographic source does not hand you a number in your range, it hands you bytes. Turn one byte into a number from 1 to 100 with a remainder and the skew is not one part in 1014, it is 50%: of the 256 possible bytes, the first 56 values in the range get three chances each and the remaining 44 get two.

So this page does the arithmetic properly. It works out how many bits your range actually needs, reads enough whole bytes to cover them, masks the value down to exactly that many bits — which is exact rather than approximate, because a power of two divides a power of two — and discards anything still above the range rather than folding it back in. Every number in the range ends up with precisely equal probability, not approximately equal. The same technique is what makes the Password Generator honest, and for the same reason.

Drawing without repeats is where generators actually break

Asking for six different numbers is a different operation from asking for six numbers, and two wrong ways of doing it are everywhere.

The first is to draw and discard duplicates until enough unique values have appeared. It is correct, and its cost climbs steeply as the count approaches the size of the range: asking for ten different numbers between one and ten means the last one has a one-in-ten chance of being useful on each attempt, and the last of a million numbers from a million has a one-in-a-million chance — a million attempts, on average, for one number.

The second is to shuffle by sorting — array.sort(() => Math.random() - 0.5), the single most copied snippet in this corner of the web. It is not a shuffle. It hands the sort a comparator that gives a different answer each time it is asked the same question, and every sorting algorithm is built on the assumption that this never happens; the result reflects the algorithm's internals, not chance. Measured over 200,000 shuffles of six items in Chrome's engine: the first item finished first 56,915 times where 33,333 was expected — 71% more often than it should — and finished third only about 20,000 times. Every item had a position it favored. Anyone drawing a running order that way has been handing out an advantage.

This page uses a partial Fisher–Yates shuffle, which picks each value in a single step and never revisits one, over a sparse map rather than a real array. That last detail is what lets you draw six numbers from one to a billion: the range is never built, only the handful of positions actually touched.

What this page cannot do

It cannot prove to anyone that a draw was fair. Nothing that produces a result and then describes it can — once the numbers exist, there is nothing to distinguish a single honest draw from the twentieth attempt at one, and any page claiming otherwise is selling you a badge.

If a result has to be accepted by people who were not watching, the order of operations has to change rather than the tool: commit publicly to something before the draw — a seed you publish, or a future public number like a national lottery result — so that afterwards anyone can check the outcome followed from it. That is a genuinely different procedure, and saying so is more useful than a reassurance.

Nothing is sent

This is a static page with no server behind it, so there is structurally nowhere for a drawn number to go. The first draw happens inside your browser a moment after the page finishes loading, never while the page is being built, because a number computed at build time would be baked into the page and handed to every visitor identically. Load the page twice and the draws differ, and neither ever appears in the page's own HTML.

Questions

Is this actually random?

It is drawn from crypto.getRandomValues, your browser’s cryptographic random source — the same one a password manager uses. That is a stronger claim than most generators can make, because nearly all of them use Math.random, which is not cryptographic. What none of us can offer is proof: you cannot tell a good source from a bad one by looking at the numbers it produced, which is exactly why this page names its source instead of asking you to assume one.

What is wrong with Math.random?

Not its distribution — it is close enough to uniform that you will never catch it out by counting. The problem is that it is predictable. It is a deterministic generator with a small internal state, and that state can be recovered from a short run of its own output; once someone has it, every number it will produce next, and every number it already produced, can be computed. That is irrelevant when you are picking a background color, and it is the whole game the moment the number decides something in front of other people — a giveaway winner, a running order, a tiebreak.

Do other generators give some numbers more often than others?

Essentially no, and it is worth being precise because this claim gets repeated a lot. The usual implementation, Math.floor(Math.random() * n), does have an uneven mapping — but for a range of 100 the unevenness is about one part in 10^14, and it grows only in proportion to the range. You could draw a number every nanosecond for the age of the universe and not gather the evidence to notice it on a range of that size. Real modulo bias appears when a value is built from raw bytes: mapping one byte onto a range of 100 with a remainder gives the first 56 numbers a 50% advantage. This page draws from bytes, so it has to handle that — and does, by discarding values that would skew the result instead of folding them back in.

Can you prove to someone else that my draw was fair?

No, and neither can any other page. Once a draw has happened, nothing you can show afterwards distinguishes a fair result from one that was drawn twenty times until it came out the right way. That is a property of the situation, not a shortcoming of this tool. If you need a result other people will accept, the order of operations has to change: commit to something before you draw — a published seed, a future public event like a lottery number — so that anyone can check afterwards that the outcome followed from it.

Why is "no repeats" a separate option?

Because it is a different draw, and it is where implementations actually go wrong. The naive approach is to keep drawing and throw away anything already seen, which is correct but gets steeply more expensive as the count approaches the size of the range — the last of ten numbers from one to ten takes ten attempts on average, and the last of a million from a million takes a million. The other common approach, shuffling with sort(() => Math.random() - 0.5), is not a shuffle at all. This page uses a partial Fisher–Yates over a sparse map, which draws each number in one step and never revisits one.

What is wrong with shuffling by sorting?

It hands the sort a comparator that answers differently every time it is asked, which every sort algorithm is entitled to assume never happens — so the result reflects the algorithm’s internals rather than chance. It is not subtle. Measured over 200,000 shuffles of six items in Chrome’s engine, the first item finished first 56,915 times against an expected 33,333 — 71% more often than it should — and finished third only about 20,000 times. Every item had a position it favored. It is the most widely copied shuffle on the web and it produces a visibly rigged order.

How large a range can I use?

Up to about 9 quadrillion — 2^53, the point where whole numbers stop being exact in a browser. Past it a "number" would be an approximation of itself, and quietly rounding your range is worse than saying so, so the page refuses instead. Drawing a handful of numbers from an enormous range is cheap here: the no-repeat draw never builds the range in memory, so six numbers from one to a billion cost six steps rather than a billion.

What does "different results were possible" mean?

For a draw without repeats of more than one number, it is how many distinct results the draw could have produced — the binomial coefficient. Picking 6 from 49 has 13,983,816 possible outcomes, which is the figure behind the odds on a lottery ticket. It is shown only when it means something and only when it can be stated exactly; a figure that is quietly wrong in its last six digits would be worse than no figure at all.

Is anything about my draw sent anywhere?

No. This is a static page with no server behind it, and the draw happens in your browser. The first number appears a moment after the page loads rather than while the page is being built — deliberately, because a number computed at build time would be the same number for every visitor. Load the page twice and you get two different draws, and the value never appears in the page’s own HTML.

Can I use this to flip a coin or roll dice?

Yes — the Coin flip, Roll a d6 and Roll a d20 presets set the range for you. There is one honest limit worth naming: this is a number generator, so a coin flip is the range 1 to 2, and the page tells you which number stands for which side rather than printing "Heads" or "Tails" — this tool only ever draws a number, and showing a word it did not actually produce would be a small lie dressed up as a convenience.

  • Random Picker

    Pick winners from a list — and, if the result has to convince other people, from a seed you publish first so anyone can re-run the draw.

  • Password Generator

    Generate a strong password from your browser’s cryptographic randomness. Nothing is sent anywhere.

  • UUID Generator

    Generate version 4 or version 7 UUIDs from your browser’s cryptographic randomness.