
🎲 How to generate a random integer in a range with JavaScript
Random numbers are needed everywhere. Order IDs in online stores, password reset codes, dice rolls in browser games, raffle winner selection. And almost always developers write the same line: Math.random().
But between "get a random decimal from 0 to 1" and "get a random integer from 5 to 20" lies a chasm of three operations where beginners regularly make mistakes: Math.floor and Math.ceil, plus one or not plus, confusion that leads to either range overflow or uneven distribution.
Let's break down the formula to the last parenthesis, write a working generator in pure HTML+CSS+JS, and look where Math.random() falls short.
💡 Quick overview:
- Break down the formula Math.floor(Math.random() * (max - min + 1)) + min, understand each operation.
- Learn why only Math.floor works, not Math.ceil or Math.round, with examples of range distortions.
- Copy a ready-made HTML generator: two fields, a button, result output, pure JS, no frameworks.
- Master Crypto.getRandomValues when Math.random isn't suitable and you need a cryptographically secure alternative.
How Math.random() works
Math.random() is a static method of the built-in Math object. It takes no arguments and returns a pseudo-random floating-point number in the range [0, 1), according to the MDN specification. The square bracket at zero means "inclusive," the round bracket at one means "exclusive." So you might get 0.0, a value around 0.372, or something close to 0.999, but you will never get exactly 1.0.
The distribution is approximately uniform. The implementation is built into the engine (V8, SpiderMonkey, JavaScriptCore), and the developer cannot choose or reset the specific algorithm (usually xorshift128+); the seed is set by the engine at startup.
By itself, Math.random() is useless for practical tasks. Games need integers, lotteries need integers within a range, cryptography needs cryptographically secure entropy that Math.random() lacks. That's why a range conversion formula is always wrapped around it.
The formula: random integer in range [min, max]
The basic formula that covers the vast majority of cases in web development:
1 function randomInt(min, max) { 2 return Math.floor(Math.random() * (max - min + 1)) + min; 3 }
Let's break it down with a learning example where min = 5 and max = 10, based on the Math.random documentation:
- Suppose
Math.random()returned a valueRin the range [0, 1). max - min + 1=10 - 5 + 1=6, the number of possible integer outcomes: 5, 6, 7, 8, 9, 10.R * 6scaled the random decimal to the width of the range.Math.floor(R * 6)rounded down by discarding the fractional part. Now we have an index from 0 to 5.index + minshifted bymin. Done: a random integer from 5 to 10 inclusive.
The same formula as a one-liner:
1 const roll = Math.floor(Math.random() * (max - min + 1)) + min;
Why Math.floor, not Math.ceil or Math.round
The choice of rounding method critically affects distribution. Let's demonstrate with a learning example using the range from 1 to 3 (all values except interval boundaries are calculated). The approach is described in the canonical StackOverflow answer.
With Math.floor and the formula (max - min + 1):
- If
Math.random()falls in the first third of the range [0, 1): multiplication by 3 gives a value from 0 to almost 1,Math.floordiscards the fractional part, producing index 0, plusminyields 1 (exactly one third of cases). - If
Math.random()is in the middle third: multiplication by 3 gives from 1 to almost 2,Math.floor→ index 1, plusmin→ 2 (another third). - If
Math.random()is in the last third: multiplication by 3 gives from 2 to almost 3,Math.floor→ index 2, plusmin→ 3 (the last third).
Uniform distribution.
What happens with Math.ceil? Math.ceil(Math.random() * 3) gives 1, 2, 3, but 1 has a negligible chance (only when Math.random() is exactly 0, which almost never happens). Edge values are distorted.
Math.round is also non-uniform: edge values get half the chance compared to middle values. That's why random integer generation uses exclusively Math.floor.
Complete example: generator in HTML, CSS, and JavaScript
A working page you can save as .html and open in a browser. Two input fields, a button, result on a green background.
1 <!DOCTYPE html> 2 <html lang="ru"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Генератор случайных чисел</title> 6 <style> 7 body { 8 font-family: system-ui, sans-serif; 9 max-width: 400px; 10 margin: 50px auto; 11 padding: 0 16px; 12 } 13 label { 14 display: block; 15 margin-top: 12px; 16 font-weight: 600; 17 } 18 input { 19 width: 100%; 20 padding: 8px; 21 margin-top: 4px; 22 font-size: 16px; 23 box-sizing: border-box; 24 } 25 button { 26 margin-top: 16px; 27 padding: 10px 24px; 28 font-size: 16px; 29 cursor: pointer; 30 } 31 .result { 32 margin-top: 20px; 33 font-size: 24px; 34 font-weight: 700; 35 color: #2e7d32; 36 } 37 </style> 38 </head> 39 <body> 40 41 <h1>Случайное число в диапазоне</h1> 42 43 <label for="minInput">От:</label> 44 <input type="number" id="minInput" value="1"> 45 46 <label for="maxInput">До:</label> 47 <input type="number" id="maxInput" value="100"> 48 49 <button id="generateBtn">Сгенерировать</button> 50 51 <div class="result" id="resultDisplay"></div> 52 53 <script> 54 function randomInt(min, max) { 55 return Math.floor(Math.random() * (max - min + 1)) + min; 56 } 57 58 const minInput = document.getElementById('minInput'); 59 const maxInput = document.getElementById('maxInput'); 60 const generateBtn = document.getElementById('generateBtn'); 61 const resultDisplay = document.getElementById('resultDisplay'); 62 63 generateBtn.addEventListener('click', () => { 64 const min = parseInt(minInput.value, 10); 65 const max = parseInt(maxInput.value, 10); 66 67 if (isNaN(min) || isNaN(max)) { 68 resultDisplay.textContent = 'Введите оба числа'; 69 return; 70 } 71 if (min > max) { 72 resultDisplay.textContent = '«От» не может быть больше «До»'; 73 return; 74 } 75 76 const result = randomInt(min, max); 77 resultDisplay.textContent = `Результат: ${result}`; 78 }); 79 </script> 80 81 </body> 82 </html>
The code is intentionally written in pure JavaScript, without frameworks or bundlers, so it can be copied and run instantly without npm install. The randomInt function takes min and max, returning an integer inclusive on both ends. The button handler reads values from the fields, validates them, and displays the result.
When Math.random() isn't enough: Crypto.getRandomValues()
Math.random() is a pseudo-random generator. It's sufficient for games, animations, A/B tests, and selecting a random array element. But for tasks where predictability means vulnerability, it's not suitable: password reset tokens, API keys, cryptographic nonces, one-time link generators.
Imagine: you send a user a password reset link with a token generated via Math.random(). Knowing the seed and algorithm (which are standard for the engine), an attacker can reconstruct the sequence and guess the token. That's exactly why any security-related code must use a cryptographically secure source of randomness.
For such scenarios, the Web Crypto API exists: crypto.getRandomValues(). It uses the operating system's cryptographically secure entropy source and fills the provided typed array with random values.
Generating a cryptographically secure random integer in a range:
1 function secureRandomInt(min, max) { 2 const range = max - min + 1; 3 const maxSafeVal = Math.floor(256 ** 4 / range) * range; 4 const buffer = new Uint32Array(1); 5 6 do { 7 crypto.getRandomValues(buffer); 8 } while (buffer[0] >= maxSafeVal); 9 10 return min + (buffer[0] % range); 11 }
This uses rejection sampling: the function requests a random 32-bit value and rejects those that fall outside the evenly divisible range. This eliminates modulo bias, when some values occur more frequently than others.
In practice, Math.random() is sufficient for most web applications. But if you're writing a generator for one-time links or confirmation codes, use crypto.getRandomValues().
Video: generating a random number in JavaScript
A short demonstration from the dcode channel, breaking down Math.random() and the range formula with a live example in the browser console:
⁉️🤔 Frequently asked questions
Does the formula Math.floor(Math.random() * (max - min + 1)) + min include the upper boundary?
Yes, it does.
max - min + 1gives the number of possible integer outcomes, andMath.floorcombined with+ minensures thatmaxis reachable. For example, withmin=1, max=3you get 1, 2, or 3; all three values are possible.
Can you use Math.ceil instead of Math.floor?
Technically yes, but the distribution becomes non-uniform. With
Math.ceil(Math.random() * range), the valueminwill only occur whenMath.random()returns exactly 0, a vanishingly rare event.Math.floorgives each integer in the range an equal chance, which is why the standard formula uses it.
Is Math.random() truly a random number?
No, it's a pseudo-random number. The JavaScript engine uses a deterministic algorithm (usually xorshift128+) that produces a statistically uniform sequence, but knowing the seed allows predicting all subsequent values. For cryptography this is unacceptable; use
crypto.getRandomValues().
How do you generate a random floating-point number in a range?
Remove
Math.floorand+ 1:Math.random() * (max - min) + min. This gives a decimal frommininclusive tomaxexclusive. If you need the upper end inclusive too, replacemax - minwithmax - min + Number.EPSILON, but in practice decimal ranges rarely require upper boundary inclusivity.
Which is faster: Math.random() or crypto.getRandomValues()?
Math.random()is orders of magnitude faster. In V8 benchmarks the difference reaches a hundredfold gap or more, becausecrypto.getRandomValues()makes a system call to/dev/urandom(Linux) or equivalent, whileMath.random()is a purely in-process PRNG. For generating thousands of values in a loop, useMath.random(); for a single security token, usecrypto.getRandomValues().
Random number in 30 seconds: what to remember
The workhorse is Math.floor(Math.random() * (max - min + 1)) + min. Remember three rules: always Math.floor (not ceil, not round), always + 1 in the multiplier (so max is reachable), always + min at the end (to shift the range). These three operations cover everything from dice rolls to selecting a random winner.
For password reset codes and tokens, use crypto.getRandomValues(). Slower, but cryptographically secure.
If you just want to try it out, copy the HTML example above, save it as a file, and open it in a browser. No dependencies, no bundlers. Works anywhere there's a <script>.



