
🎲 Cómo generar un número entero aleatorio en un rango con JavaScript
Los números aleatorios se necesitan en todas partes. Identificadores de pedido en tiendas en línea, códigos de restablecimiento de contraseña, tiradas de dados en juegos de navegador, selección del ganador de un sorteo. Y casi siempre los desarrolladores escriben la misma línea: Math.random().
Pero entre «obtener un decimal aleatorio de 0 a 1» y «obtener un entero aleatorio de 5 a 20» hay un abismo de tres operaciones donde los principiantes cometen errores regularmente: Math.floor y Math.ceil, sumar uno o no sumarlo, confusión que lleva a un desbordamiento del rango o a una distribución desigual.
Desglosemos la fórmula hasta el último paréntesis, escribamos un generador funcional en HTML+CSS+JS puro y veamos dónde se queda corto Math.random().
💡 Resumen rápido:
- Desglose de la fórmula Math.floor(Math.random() * (max - min + 1)) + min, comprenda cada operación.
- Aprenda por qué solo funciona Math.floor, y no Math.ceil o Math.round, con ejemplos de distorsiones del rango.
- Copie un generador HTML listo para usar: dos campos, un botón, salida del resultado, JS puro, sin frameworks.
- Domine Crypto.getRandomValues cuando Math.random no sea adecuado y necesite una alternativa criptográficamente segura.
Cómo funciona Math.random()
Math.random() es un método estático del objeto incorporado Math. No recibe argumentos y devuelve un número pseudoaleatorio de coma flotante en el rango [0, 1), según la especificación de MDN. El corchete en el cero significa «inclusivo», el paréntesis en el uno significa «exclusivo». Así que podría obtener 0.0, un valor alrededor de 0.372 o algo cercano a 0.999, pero nunca obtendrá exactamente 1.0.
La distribución es aproximadamente uniforme. La implementación está integrada en el motor (V8, SpiderMonkey, JavaScriptCore) y el desarrollador no puede elegir ni reiniciar el algoritmo específico (normalmente xorshift128+); la semilla la establece el motor al iniciarse.
Por sí solo, Math.random() es inútil para tareas prácticas. Los juegos necesitan enteros, las loterías necesitan enteros dentro de un rango, la criptografía necesita entropía criptográficamente segura de la que Math.random() carece. Por eso siempre se envuelve con una fórmula de conversión de rango.
La fórmula: entero aleatorio en el rango [min, max]
La fórmula básica que cubre la gran mayoría de los casos en desarrollo web:
1 function randomInt(min, max) { 2 return Math.floor(Math.random() * (max - min + 1)) + min; 3 }
Vamos a desglosarla con un ejemplo didáctico donde min = 5 y max = 10, basado en la documentación de Math.random:
- Supongamos que
Math.random()devolvió un valorRen el rango [0, 1). max - min + 1=10 - 5 + 1=6, el número de posibles resultados enteros: 5, 6, 7, 8, 9, 10.R * 6escaló el decimal aleatorio al ancho del rango.Math.floor(R * 6)redondeó hacia abajo descartando la parte fraccionaria. Ahora tenemos un índice de 0 a 5.index + mindesplazó pormin. Listo: un entero aleatorio de 5 a 10 inclusive.
La misma fórmula en una sola línea:
1 const roll = Math.floor(Math.random() * (max - min + 1)) + min;
Por qué Math.floor, y no Math.ceil o Math.round
La elección del método de redondeo afecta críticamente a la distribución. Demostrémoslo con un ejemplo didáctico usando el rango de 1 a 3 (todos los valores excepto los límites del intervalo son calculados). El enfoque se describe en la respuesta canónica de StackOverflow.
Con Math.floor y la fórmula (max - min + 1):
- Si
Math.random()cae en el primer tercio del rango [0, 1): la multiplicación por 3 da un valor de 0 a casi 1,Math.floordescarta la parte fraccionaria, produciendo el índice 0, másminproduce 1 (exactamente un tercio de los casos). - Si
Math.random()está en el tercio medio: la multiplicación por 3 da de 1 a casi 2,Math.floor→ índice 1, másmin→ 2 (otro tercio). - Si
Math.random()está en el último tercio: la multiplicación por 3 da de 2 a casi 3,Math.floor→ índice 2, másmin→ 3 (el último tercio).
Distribución uniforme.
¿Qué sucede con Math.ceil? Math.ceil(Math.random() * 3) da 1, 2, 3, pero 1 tiene una probabilidad insignificante (solo cuando Math.random() es exactamente 0, lo cual casi nunca ocurre). Los valores extremos se distorsionan.
Math.round tampoco es uniforme: los valores extremos obtienen la mitad de probabilidad en comparación con los valores medios. Por eso la generación de enteros aleatorios usa exclusivamente Math.floor.
Ejemplo completo: generador en HTML, CSS y JavaScript
Una página funcional que puede guardar como .html y abrir en un navegador. Dos campos de entrada, un botón, resultado sobre fondo 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>
El código está escrito intencionadamente en JavaScript puro, sin frameworks ni empaquetadores, para que pueda copiarse y ejecutarse instantáneamente sin npm install. La función randomInt recibe min y max, devolviendo un entero inclusivo en ambos extremos. El manejador del botón lee los valores de los campos, los valida y muestra el resultado.
Cuando Math.random() no es suficiente: Crypto.getRandomValues()
Math.random() es un generador pseudoaleatorio. Es suficiente para juegos, animaciones, pruebas A/B y seleccionar un elemento aleatorio de un array. Pero para tareas donde la previsibilidad significa vulnerabilidad, no es adecuado: tokens de restablecimiento de contraseña, claves de API, nonces criptográficos, generadores de enlaces de un solo uso.
Imagine: envía a un usuario un enlace de restablecimiento de contraseña con un token generado mediante Math.random(). Conociendo la semilla y el algoritmo (que son estándar para el motor), un atacante puede reconstruir la secuencia y adivinar el token. Esa es exactamente la razón por la que cualquier código relacionado con la seguridad debe usar una fuente de aleatoriedad criptográficamente segura.
Para tales escenarios existe la Web Crypto API: crypto.getRandomValues(). Utiliza la fuente de entropía criptográficamente segura del sistema operativo y llena el array tipado proporcionado con valores aleatorios.
Generación de un entero aleatorio criptográficamente seguro en un rango:
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 }
Esto usa muestreo por rechazo: la función solicita un valor aleatorio de 32 bits y rechaza aquellos que caen fuera del rango divisible uniformemente. Esto elimina el sesgo de módulo, cuando algunos valores ocurren con más frecuencia que otros.
En la práctica, Math.random() es suficiente para la mayoría de las aplicaciones web. Pero si está escribiendo un generador para enlaces de un solo uso o códigos de confirmación, use crypto.getRandomValues().
Vídeo: generación de un número aleatorio en JavaScript
Una breve demostración del canal dcode, desglosando Math.random() y la fórmula de rango con un ejemplo en vivo en la consola del navegador:
⁉️🤔 Preguntas frecuentes
¿La fórmula Math.floor(Math.random() * (max - min + 1)) + min incluye el límite superior?
Sí, lo incluye.
max - min + 1da el número de posibles resultados enteros, yMath.floorcombinado con+ minasegura quemaxsea alcanzable. Por ejemplo, conmin=1, max=3obtiene 1, 2 o 3; los tres valores son posibles.
¿Se puede usar Math.ceil en lugar de Math.floor?
Técnicamente sí, pero la distribución se vuelve no uniforme. Con
Math.ceil(Math.random() * range), el valorminsolo ocurrirá cuandoMath.random()devuelva exactamente 0, un evento extremadamente raro.Math.floorda a cada entero del rango una probabilidad igual, razón por la cual la fórmula estándar lo utiliza.
¿Es Math.random() un número verdaderamente aleatorio?
No, es un número pseudoaleatorio. El motor de JavaScript utiliza un algoritmo determinista (normalmente xorshift128+) que produce una secuencia estadísticamente uniforme, pero conocer la semilla permite predecir todos los valores subsiguientes. Para criptografía esto es inaceptable; use
crypto.getRandomValues().
¿Cómo se genera un número aleatorio de coma flotante en un rango?
Elimine
Math.floory+ 1:Math.random() * (max - min) + min. Esto da un decimal desdemininclusivo hastamaxexclusivo. Si también necesita incluir el extremo superior, reemplacemax - minpormax - min + Number.EPSILON, pero en la práctica los rangos decimales rara vez requieren inclusividad del límite superior.
¿Qué es más rápido: Math.random() o crypto.getRandomValues()?
Math.random()es órdenes de magnitud más rápido. En los benchmarks de V8 la diferencia alcanza una brecha de cien veces o más, porquecrypto.getRandomValues()realiza una llamada al sistema a/dev/urandom(Linux) o equivalente, mientras queMath.random()es un PRNG puramente en proceso. Para generar miles de valores en un bucle, useMath.random(); para un único token de seguridad, usecrypto.getRandomValues().
Número aleatorio en 30 segundos: qué recordar
El caballo de batalla es Math.floor(Math.random() * (max - min + 1)) + min. Recuerde tres reglas: siempre Math.floor (no ceil, no round), siempre + 1 en el multiplicador (para que max sea alcanzable), siempre + min al final (para desplazar el rango). Estas tres operaciones cubren todo, desde tiradas de dados hasta la selección de un ganador aleatorio.
Para códigos de restablecimiento de contraseña y tokens, use crypto.getRandomValues(). Más lento, pero criptográficamente seguro.
Si solo quiere probarlo, copie el ejemplo HTML anterior, guárdelo como archivo y ábralo en un navegador. Sin dependencias, sin empaquetadores. Funciona en cualquier lugar donde haya un <script>.



