Where the randomness comes from
This generator uses your browser's crypto.getRandomValues — the cryptographically secure random
source browsers use for encryption keys — rather than Math.random. Everything runs locally in your
browser; nothing is sent to a server, and refreshing or pressing 🎲 Generate again draws a
completely fresh set.
Why rejection sampling matters
accept a raw 64-bit draw only if it is below the largest exact multiple of the range size
The naive approach — take a random value and apply modulo the range size — is subtly biased: unless the range
divides the generator's 2⁶⁴ possibilities exactly, the leftover values wrap around and make the low end of your
range slightly more likely. (The common Math.floor(Math.random() × n) pattern shares this problem,
on top of Math.random's weaker, non-cryptographic source.) Rejection sampling fixes it: draws that
fall into the biased leftover zone are simply discarded and redrawn, so every integer from min to max is exactly
equally likely. Rejections are rare, so this costs almost nothing.
Worked example
With the defaults — min 1, max 100, one number — each of the 100 values has exactly a 1% chance. Ask for 5 numbers with no duplicates and the tool behaves like drawing 5 balls from a bag of 100 without putting them back: no repeats, every unordered set equally likely.
Limits and validation
Whole numbers only; min must not exceed max; the range can span up to 10¹⁵ values; and you can draw up to 1,000 numbers at once. "No duplicates" additionally needs the range to be at least as large as the count — you can't deal 10 unique cards from a 5-card deck. Tick Sort results to get the output in ascending order instead of draw order.