Skip to content

Todo para WordPress, el desarrollo web — y mucho más

🎲 Cómo generar un número entero aleatorio en un rango con JavaScript

🎲 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:

1function 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 valor R en 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 * 6 escaló 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 + min desplazó por min. Listo: un entero aleatorio de 5 a 10 inclusive.

La misma fórmula en una sola línea:

1const 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.floor descarta la parte fraccionaria, produciendo el índice 0, más min produce 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ás min2 (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ás min3 (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:

1function 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 + 1 da el número de posibles resultados enteros, y Math.floor combinado con + min asegura que max sea alcanzable. Por ejemplo, con min=1, max=3 obtiene 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 valor min solo ocurrirá cuando Math.random() devuelva exactamente 0, un evento extremadamente raro. Math.floor da 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.floor y + 1: Math.random() * (max - min) + min. Esto da un decimal desde min inclusivo hasta max exclusivo. Si también necesita incluir el extremo superior, reemplace max - min por max - 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, porque crypto.getRandomValues() realiza una llamada al sistema a /dev/urandom (Linux) o equivalente, mientras que Math.random() es un PRNG puramente en proceso. Para generar miles de valores en un bucle, use Math.random(); para un único token de seguridad, use crypto.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>.