Random number generator 1 to 1000
A random number generator for 1 to 1000 that runs in your browser: one draw from 1,000 equally likely values, debiased so none of them is favored.
Random number
- Where this came from Your browser's cryptographically secure generator, not Math.random(). V8 implements Math.random() with xorshift128+, whose internal state can be recovered from a short run of its own output. That is fine for shuffling a playlist and unusable for anything anybody would call a secret.
- crypto.getRandomValues()
- Debiased by 2^32 is not a multiple of 1,000, so 296 values would get one extra chance each under plain modulo. Those words are drawn again instead of used, which costs 0.000007% of draws and makes every outcome exactly equally likely.
- rejection sampling, discarding 296 of 2^32 words
- Skew avoided How much more likely the favored outcomes would have been under
getRandomValues() % range. For small ranges it is far below anything observable; the reason to do it properly is that the same line of code is wrong by nearly 2x for ranges near 2^31, and nobody rewrites it when the range changes. - 0.00002328%
- Range size
- 1,000 values
- Entropy 1 independent draw from 1,000 values. For comparison, a six-character lowercase password carries about 28 bits and a four-word passphrase from a 7,776-word list about 51.
- 10.0 bits
- The numbers in the HTML were drawn once when the site was built, so without JavaScript every visitor sees the same ones. With JavaScript on, which is the normal case, the draw happens in your own browser, from your own generator, and nothing is sent anywhere.
How the Random Number Generator works
This generator draws one integer from 1 to 1000 inclusive: 1,000 possible values, each with probability exactly 1 in 1,000.
A thousand values is where a range stops being memorable and starts being a sample identifier: random row selection, a test case index, an anonymous participant number. The remainder when 2^32 is divided by 1000 is 296, so 296 words are rejected, about one draw in 14.5 million. At this size the chance of two independent draws colliding is already meaningful: pick 38 numbers from 1 to 1000 and it is more likely than not that two of them match. That is the birthday problem, and it is the reason a thousand-value range is too small to use as an identifier for anything that matters.
The draw happens in your browser, from crypto.getRandomValues(), which reads your operating system's cryptographically secure generator. It is not Math.random(): that is xorshift128+ in V8, fast and statistically fine for a game, and predictable to anyone who sees a short run of its output. Nothing about your draw is sent anywhere, because there is nowhere for it to be sent: the page is static and the generator is local.
A 32-bit word has 4,294,967,296 possible values and 1,000 does not divide it evenly; the remainder is 296. Under the usual word % 1,000, those 296 values would each get one extra chance, making 296 outcomes very slightly more likely than the rest. This generator rejects those words and draws again, which costs about one draw in 14,510,025 and makes the distribution exactly uniform instead of nearly so. For a range this size the skew being removed is around 0.000023%. That is undetectable in practice, but the same code is wrong by nearly 2x for ranges near 2^31, which is the real reason to write it correctly.
One draw from this range carries about 10.0 bits of entropy. For scale, a six-character lowercase password is roughly 28 bits and anything used as a secret wants 70 or more.
One thing about how the result reaches you: the site is statically hosted, so the number in the HTML was drawn once when the site was built. If you have JavaScript turned off, that is what you are looking at, and every other such visitor sees the same thing. With JavaScript on, the generator redraws immediately from your own browser. A generator that quietly serves one cached "random" value to everybody is broken, which is why the build-time draw is labeled.
Random Number Generator FAQ
How do I get a random number between 1 and 1000?
The generator above does it on load and on every press. It draws from your browser's crypto.getRandomValues() and discards the 296 words that would skew the result before mapping it onto the 1,000 values.
Is every number in this range equally likely?
Yes, exactly. The 296 words that would have made some outcomes marginally likelier are rejected and redrawn, so each of the 1,000 outcomes ends up with exactly 4,294,967 words behind it.
Is there anything particular about this range?
A thousand values is where a range stops being memorable and starts being a sample identifier: random row selection, a test case index, an anonymous participant number. The remainder when 2^32 is divided by 1000 is 296, so 296 words are rejected, about one draw in 14.5 million. At this size the chance of two independent draws colliding is already meaningful: pick 38 numbers from 1 to 1000 and it is more likely than not that two of them match. That is the birthday problem, and it is the reason a thousand-value range is too small to use as an identifier for anything that matters.
Can I rely on it not being predictable?
For anything short of a regulated draw, yes. The source is the same operating-system facility that generates cryptographic keys. The limit worth knowing is that it is a CSPRNG seeded from hardware entropy rather than a hardware true-random device sampling a physical process, and no software running in a browser tab can be the latter.
More from the Random Number Generator
- Random number generator 1 to 10
- Random number generator 1 to 100
- Random number between 1 and 6
- Random number from 1 to 2
- Random number generator 1-49: pick 6
- Bingo caller
- Lottery number generator