
🎲 Come generare un numero intero casuale in un intervallo con JavaScript
I numeri casuali servono ovunque. ID ordine negli shop online, codici di reset password, tiri di dado nei giochi browser, estrazione del vincitore di un concorso. E quasi sempre gli sviluppatori scrivono la stessa riga: Math.random().
Ma tra "ottenere un decimale casuale da 0 a 1" e "ottenere un intero casuale da 5 a 20" c'è un abisso di tre operazioni in cui i principianti sbagliano regolarmente: Math.floor e Math.ceil, più uno o non più uno, confusione che porta a sforamento dell'intervallo o a distribuzione non uniforme.
Scomponiamo la formula fino all'ultima parentesi, scriviamo un generatore funzionante in HTML+CSS+JS puro e vediamo dove Math.random() non basta.
💡 Panoramica rapida:
- Scomposizione della formula Math.floor(Math.random() * (max - min + 1)) + min, comprensione di ogni operazione.
- Perché funziona solo Math.floor, non Math.ceil o Math.round, con esempi di distorsione dell'intervallo.
- Copia un generatore HTML già pronto: due campi, un pulsante, output del risultato, JS puro, nessun framework.
- Padroneggia Crypto.getRandomValues quando Math.random non è adatto e ti serve un'alternativa crittograficamente sicura.
Come funziona Math.random()
Math.random() è un metodo statico dell'oggetto nativo Math. Non accetta argomenti e restituisce un numero a virgola mobile pseudo-casuale nell'intervallo [0, 1), secondo la specifica MDN. La parentesi quadra sullo zero significa "inclusivo", la parentesi tonda sull'uno significa "esclusivo". Quindi potresti ottenere 0.0, un valore intorno a 0.372 o qualcosa vicino a 0.999, ma non otterrai mai esattamente 1.0.
La distribuzione è approssimativamente uniforme. L'implementazione è integrata nel motore (V8, SpiderMonkey, JavaScriptCore) e lo sviluppatore non può scegliere o reimpostare l'algoritmo specifico (di solito xorshift128+); il seed viene impostato dal motore all'avvio.
Di per sé, Math.random() è inutile per compiti pratici. I giochi hanno bisogno di interi, le lotterie di interi entro un intervallo, la crittografia ha bisogno di entropia crittograficamente sicura che Math.random() non possiede. Ecco perché ci si avvolge sempre intorno una formula di conversione in intervallo.
La formula: intero casuale nell'intervallo [min, max]
La formula base che copre la stragrande maggioranza dei casi nello sviluppo web:
1 function randomInt(min, max) { 2 return Math.floor(Math.random() * (max - min + 1)) + min; 3 }
Scomponiamola con un esempio didattico dove min = 5 e max = 10, basato sulla documentazione di Math.random:
- Supponiamo che
Math.random()abbia restituito un valoreRnell'intervallo [0, 1). max - min + 1=10 - 5 + 1=6, il numero di possibili risultati interi: 5, 6, 7, 8, 9, 10.R * 6ha scalato il decimale casuale all'ampiezza dell'intervallo.Math.floor(R * 6)ha arrotondato per difetto scartando la parte frazionaria. Ora abbiamo un indice da 0 a 5.index + minha traslato dimin. Fatto: un intero casuale da 5 a 10 inclusi.
La stessa formula in una riga:
1 const roll = Math.floor(Math.random() * (max - min + 1)) + min;
Perché Math.floor, non Math.ceil o Math.round
La scelta del metodo di arrotondamento incide in modo critico sulla distribuzione. Dimostriamolo con un esempio didattico usando l'intervallo da 1 a 3 (tutti i valori tranne i confini dell'intervallo sono calcolati). L'approccio è descritto nella risposta canonica su StackOverflow.
Con Math.floor e la formula (max - min + 1):
- Se
Math.random()cade nel primo terzo dell'intervallo [0, 1): la moltiplicazione per 3 dà un valore da 0 a quasi 1,Math.floorscarta la parte frazionaria, producendo l'indice 0, piùmindà 1 (esattamente un terzo dei casi). - Se
Math.random()è nel terzo centrale: la moltiplicazione per 3 dà da 1 a quasi 2,Math.floor→ indice 1, piùmin→ 2 (un altro terzo). - Se
Math.random()è nell'ultimo terzo: la moltiplicazione per 3 dà da 2 a quasi 3,Math.floor→ indice 2, piùmin→ 3 (l'ultimo terzo).
Distribuzione uniforme.
Cosa succede con Math.ceil? Math.ceil(Math.random() * 3) dà 1, 2, 3, ma 1 ha una probabilità trascurabile (solo quando Math.random() è esattamente 0, cosa che quasi non accade mai). I valori estremi sono distorti.
Anche Math.round non è uniforme: i valori estremi hanno metà della probabilità rispetto a quelli centrali. Ecco perché la generazione di interi casuali usa esclusivamente Math.floor.
Esempio completo: generatore in HTML, CSS e JavaScript
Una pagina funzionante che puoi salvare come .html e aprire nel browser. Due campi di input, un pulsante, risultato su sfondo verde.
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>
Il codice è scritto intenzionalmente in JavaScript puro, senza framework o bundler, così da poter essere copiato ed eseguito all'istante senza npm install. La funzione randomInt prende min e max, restituendo un intero inclusivo su entrambi gli estremi. Il gestore del pulsante legge i valori dai campi, li valida e mostra il risultato.
Quando Math.random() non basta: Crypto.getRandomValues()
Math.random() è un generatore pseudo-casuale. È sufficiente per giochi, animazioni, test A/B e selezione di un elemento casuale da un array. Ma per compiti in cui la prevedibilità significa vulnerabilità, non è adatto: token di reset password, chiavi API, nonce crittografici, generatori di link monouso.
Immagina: invii a un utente un link di reset password con un token generato via Math.random(). Conoscendo il seed e l'algoritmo (che sono standard per il motore), un attaccante può ricostruire la sequenza e indovinare il token. È esattamente per questo che qualsiasi codice legato alla sicurezza deve usare una fonte di casualità crittograficamente sicura.
Per questi scenari esiste la Web Crypto API: crypto.getRandomValues(). Usa la fonte di entropia crittograficamente sicura del sistema operativo e riempie l'array tipizzato fornito con valori casuali.
Generare un intero casuale crittograficamente sicuro in un intervallo:
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 }
Qui si usa il campionamento per rigetto: la funzione richiede un valore casuale a 32 bit e scarta quelli che cadono fuori dall'intervallo uniformemente divisibile. Questo elimina il modulo bias, cioè quando alcuni valori occorrono più frequentemente di altri.
In pratica, Math.random() è sufficiente per la maggior parte delle applicazioni web. Ma se stai scrivendo un generatore di link monouso o codici di conferma, usa crypto.getRandomValues().
Video: generare un numero casuale in JavaScript
Una breve dimostrazione dal canale dcode, che scompone Math.random() e la formula dell'intervallo con un esempio dal vivo nella console del browser:
⁉️🤔 Domande frequenti
La formula Math.floor(Math.random() * (max - min + 1)) + min include il limite superiore?
Sì, lo include.
max - min + 1dà il numero di possibili risultati interi, eMath.floorcombinato con+ mingarantisce chemaxsia raggiungibile. Ad esempio, conmin=1, max=3ottieni 1, 2 o 3; tutti e tre i valori sono possibili.
Si può usare Math.ceil invece di Math.floor?
Tecnicamente sì, ma la distribuzione diventa non uniforme. Con
Math.ceil(Math.random() * range), il valoreminsi verificherà solo quandoMath.random()restituisce esattamente 0, un evento di probabilità infinitesima.Math.floordà a ogni intero nell'intervallo la stessa probabilità, ed è per questo che la formula standard lo usa.
Math.random() è davvero un numero casuale?
No, è un numero pseudo-casuale. Il motore JavaScript usa un algoritmo deterministico (di solito xorshift128+) che produce una sequenza statisticamente uniforme, ma conoscere il seed permette di prevedere tutti i valori successivi. Per la crittografia questo è inaccettabile; usa
crypto.getRandomValues().
Come si genera un numero a virgola mobile casuale in un intervallo?
Rimuovi
Math.floore+ 1:Math.random() * (max - min) + min. Questo dà un decimale damininclusivo amaxesclusivo. Se ti serve inclusivo anche il limite superiore, sostituiscimax - minconmax - min + Number.EPSILON, ma in pratica gli intervalli decimali raramente richiedono l'inclusività del limite superiore.
Qual è più veloce: Math.random() o crypto.getRandomValues()?
Math.random()è ordini di grandezza più veloce. Nei benchmark V8 la differenza raggiunge un divario di cento volte o più, perchécrypto.getRandomValues()effettua una chiamata di sistema a/dev/urandom(Linux) o equivalente, mentreMath.random()è un PRNG puramente in-process. Per generare migliaia di valori in un ciclo, usaMath.random(); per un singolo token di sicurezza, usacrypto.getRandomValues().
Numero casuale in 30 secondi: cosa ricordare
Il cavallo di battaglia è Math.floor(Math.random() * (max - min + 1)) + min. Ricorda tre regole: sempre Math.floor (non ceil, non round), sempre + 1 nel moltiplicatore (così max è raggiungibile), sempre + min alla fine (per traslare l'intervallo). Queste tre operazioni coprono tutto, dai tiri di dado alla selezione di un vincitore casuale.
Per codici di reset password e token, usa crypto.getRandomValues(). Più lento, ma crittograficamente sicuro.
Se vuoi solo provarlo, copia l'esempio HTML qui sopra, salvalo come file e aprilo nel browser. Nessuna dipendenza, nessun bundler. Funziona ovunque ci sia un <script>.



