Generate uniform random integers in any range, with or without repeats. Uses the browser’s crypto.getRandomValues API for real entropy (the same source used for cryptographic key generation) and rejection sampling to eliminate modulo bias. Useful for lottery picks, test fixtures, shuffling, dice rolls, and anywhere you need unbiased samples from a range.
How it works
Three inputs: min (lower bound, inclusive), max (upper bound, inclusive), count (how many values you want). One checkbox: unique — whether the values can repeat.
With replacement (unique = off): each value is drawn independently using rejection sampling to avoid modulo bias. Each draw is a fresh 32-bit random integer from crypto.getRandomValues, reduced to the target range by rejecting outcomes that fall into the biased tail. Over many draws, every value in [min, max] appears with equal probability.
Without replacement (unique = on): the result is guaranteed to be all-distinct. When count is small relative to range, the tool uses rejection sampling with a Set to track seen values. When count approaches range, it switches to a Fisher-Yates partial shuffle (which is faster when you’re picking most of the values). The crossover is at count / range = 0.3.
Example: dice rolls
Min = 1, max = 6, count = 10, unique = off. You get a list of 10 dice rolls — possibly with repeats, just like real dice. Flip the checkbox on and you’d only get 6 values (since 7 unique values from a 6-value range is impossible, the tool errors). For multi-die rolls with standard polyhedral sizes (d4, d6, d8, d10, d12, d20, d100) and history, the coin flip and dice roller is the tabletop-specific version.
Example: lottery draw
Min = 1, max = 49, count = 6, unique = on. You get six distinct numbers from 1 to 49 — a standard 6/49 lottery draw. Because the range is large (49) and the count is small (6), rejection sampling is fast: on average it needs about 6.4 draws to find 6 unique values.
Example: shuffling a deck
Min = 1, max = 52, count = 52, unique = on. This triggers the Fisher-Yates shuffle path because count / range = 1.0. The tool generates every integer 1–52 in random order — a complete shuffled permutation.
Example: picking a password character pool
Min = 33, max = 126, count = 16, unique = off. You get 16 random printable ASCII codepoints, which you could map to characters for a random password. (Though for actual password generation, prefer the password generator — this one doesn’t enforce character-class requirements or deduplicate based on readability.)
Why crypto.getRandomValues
Math.random is a pseudo-random generator — fast but predictable if you know the algorithm’s state. Browsers use xorshift-like algorithms that pass statistical tests but aren’t cryptographically secure. crypto.getRandomValues pulls from the operating system’s entropy pool (/dev/urandom on Linux/macOS, BCryptGenRandom on Windows) which is gathered from genuinely unpredictable sources (disk timing jitter, keyboard input timing, network interrupt timing, etc.).
For random dice or lottery picks, either source is fine — the difference is invisible. For anything security-adjacent (session tokens, temporary passwords, game seeds that shouldn’t be guessable), crypto.getRandomValues is the right default. The tool uses it unconditionally and only falls back to Math.random in the extraordinarily rare case where the Crypto API isn’t available.
Rejection sampling vs. modulo bias
A naive rand32() % range has a tiny bias toward smaller values when range doesn’t evenly divide 2³². For range = 7, each of the first 4 values (0–3) gets (2³²)/7 + 1 source values mapping to it; the last 3 (4–6) get only (2³²)/7. That’s a bias of roughly 1 in 600 million per draw — undetectable in casual use, but a mathematical defect that real RNG libraries avoid.
Rejection sampling: draw a uint32, if it’s below the largest multiple of range that fits, accept; otherwise draw again. Expected number of draws is < 2, the bias is gone, and the cost is negligible.
Reproducibility
Each generation click pulls fresh OS entropy, so you won’t get the same sequence twice — which is the right default for security but makes reproducing results for testing harder. If you need deterministic sequences, use the exported mulberry32 PRNG directly in code: it’s a small seeded PRNG that produces the same output for the same seed. That’s what the unit tests do.
What this tool does not do
It doesn’t generate non-integer numbers. Floats, decimals, and probabilities aren’t supported. The tool is strictly integer-valued. For floats, a separate uniform-in-[0,1) or normal-distribution tool would be needed.
It doesn’t weight values unequally. Every value in [min, max] is equally likely. For biased sampling (e.g., draw with probabilities [0.5, 0.3, 0.2]), you need a weighted-random-choice tool.
It doesn’t save generated sequences. Each click is a fresh draw; previous results disappear. If you need persistence, copy the result out of the UI.
It doesn’t support seeding through the UI. Fresh OS entropy on every click is the default. For reproducible sequences, use the calculator module directly in code with the mulberry32 PRNG.
It doesn’t generate characters or strings. The output is always numeric. For random strings, passwords, or tokens, a dedicated password generator is the right tool.