The short answer
A computer follows instructions exactly, so it cannot invent randomness out of nothing. It either computes numbers that pass statistical tests for randomness (a pseudo random number generator, PRNG), or it measures something physically unpredictable and processes it (a true or hardware random source). Modern systems combine the two: the operating system gathers unpredictable noise and uses it to seed a cryptographically secure PRNG (CSPRNG), which then produces as many numbers as needed.
The generator on this page uses the browser's secure source through the Web Crypto API and converts it to your range without bias. Enter a Minimum and Maximum, choose How many, and press Generate.
Try it here: Random Number Generator
Open the full tool pagePseudo random generators and seeds
A PRNG keeps an internal state. Each time you ask for a number, it scrambles the state with a fixed formula and outputs part of the result. The simplest classic design, the linear congruential generator, computes the next state as (a times state plus c) modulo m. Better designs such as the Mersenne Twister (the default in Python's random module) or the xorshift family produce much higher quality sequences, and the Mersenne Twister only repeats after 2 to the power 19,937 minus 1 steps.
The seed is the starting state. The same seed always produces the same sequence. That is a feature, not a flaw, in many situations: a scientist can rerun a simulation exactly, a game can rebuild a world from a short seed code, and a test can reproduce a bug. If a program seeds from something guessable such as the current time in seconds, though, an attacker can try every likely seed and recreate the numbers.
Pseudo random vs cryptographically secure
Fast general purpose PRNGs are statistically good but predictable: after observing enough outputs, it is possible to reconstruct the internal state and predict every following number. That is fine for a particle effect in a game, not fine for a password, a lottery or a security token.
| Type | Where the numbers come from | Predictable? | Typical use |
|---|---|---|---|
| Simple PRNG (LCG, xorshift, Mersenne Twister) | A formula and a seed | Yes, from the seed or enough outputs | Simulations, games, graphics |
| CSPRNG | A formula seeded and refreshed with system noise | No, not in practice | Passwords, keys, draws, tokens |
| Hardware RNG | Physical noise such as thermal or timing jitter | No | Feeding the operating system's pool |
Where computers find real randomness
Operating systems collect small unpredictable events: the exact timing of interrupts, disk and network activity, and dedicated hardware generators built into many modern processors that sample electrical noise. This entropy is mixed into a pool and used to seed and regularly reseed a CSPRNG. Linux exposes it through getrandom and /dev/urandom, and Windows through its system cryptography functions.
Some services go further for publicity or extra assurance. Random.org uses atmospheric radio noise, and Cloudflare famously films a wall of lava lamps as one of its entropy sources. For everyday needs, the operating system's generator is already strong enough for encryption keys.
How browsers generate secure random numbers
JavaScript has two options. Math.random() returns a number between 0 and 1 from a fast PRNG (current engines use xorshift style algorithms). It is fine for animations but is not designed to be unpredictable, and the specification makes no security promise.
crypto.getRandomValues() fills an array with random bytes from the browser's CSPRNG, which is seeded by the operating system. It is available in every modern browser, works offline, and is what password generators and key generation code should use. A single call can return at most 65,536 bytes, so large jobs call it repeatedly. This generator, like the coin flip, dice roller, wheel and name picker on Anyfeat, uses crypto.getRandomValues.
Why rand() % n can be biased
A generator gives you raw values in a fixed range, for example a byte from 0 to 255. The obvious way to get a number from 0 to 5 is to take the remainder after dividing by 6 (value % 6). The problem: 256 values do not divide evenly into 6 groups. 256 is 42 times 6 plus 4, so the remainders 0 to 3 occur 43 times each and the remainders 4 and 5 only 42 times. Some results are about 2.4% more likely than others. This is called modulo bias.
With 32 bit values and a small range the bias becomes tiny, but with large ranges it grows. The standard fix is rejection sampling: find the largest multiple of n that fits in the raw range (252 in the byte example), throw away any raw value at or above it and draw again. Every remaining value maps onto the range evenly. This generator draws 32 bit values and rejects the uneven tail, so each number in your range has exactly the same probability.
A similar mistake is Math.floor(Math.random() * n) for security purposes. The rounding is fine for most ranges, but the source is predictable, so it should not be used for passwords or draws with money at stake.
Unique numbers, shuffles and common pitfalls
- Unique numbers: to draw without repeats, shuffle the full range with the Fisher Yates algorithm and take the first k, or draw and discard repeats. This generator does exactly that when No repeats is ticked, and tells you if the range is too small for the count.
- Biased shuffles: sorting a list with a random comparison function does not give a uniform shuffle. Use Fisher Yates.
- Reseeding too often: seeding a PRNG with the time in a loop can produce the same number many times in a row.
- Decimals: picking a random decimal by scaling a random fraction can make the end points less likely. This tool instead draws a whole number of steps (for 2 decimals, hundredths) so both ends are included with equal chance.
- Expecting patterns to be absent: real random output contains streaks and repeats. Seeing 7 twice in a row is not a sign of a broken generator.