Original article: Random Number Generator: How Do Computers Generate Random Numbers?

Las personas han estado usando números aleatorios durante milenios, por lo que el concepto no es nuevo. Desde la lotería en la antigua Babilonia hasta las mesas de ruleta en Monte Carlo y los juegos de dados en Las Vegas, el objetivo es dejar el resultado final al azar.

Pero dejando de lado las apuestas, la aleatoriedad tiene muchos usos en la ciencia, las estadísticas, la criptografía y más. Sin embargo, el uso de dados, monedas o medios similares como dispositivo aleatorio tiene sus limitaciones.

Debido a la naturaleza mecánica de estas técnicas, la generación de grandes cantidades de números aleatorios requiere una gran cantidad de tiempo y trabajo. Gracias al ingenio humano tenemos a nuestra disposición herramientas y métodos más poderosos.

Métodos para generar números aleatorios

Números Aleatorios Verdaderos

image-145-opt
Imagen de un dispositivo de procesamiento de salida digital de entrada analógica. Foto por Harrison Broadbent

Consideremos dos métodos principales utilizados para generar números aleatorios. El primer método se basa en un proceso físico y extrae la fuente de aleatoriedad de algún fenómeno físico que se espera que sea aleatorio.

Tal fenómeno ocurre fuera de la computadora. Se mide y ajusta por posibles sesgos debidos al proceso de medición. Los ejemplos incluyen la descomposición radiactiva, el efecto fotoeléctrico, la radiación de fondo cósmica, el ruido atmosférico (que usaremos en este artículo) y más.

Por tanto, los números aleatorios generados basándose en dicha aleatoriedad se denominan números aleatorios "verdaderos".

Consideremos dos métodos principales utilizados para generar números aleatorios. El primer método se basa en un proceso físico y extrae la fuente de aleatoriedad de algún fenómeno físico que se espera que sea aleatorio.

Tal fenómeno ocurre fuera de la computadora. Se mide y ajusta por posibles sesgos debidos al proceso de medición. Los ejemplos incluyen la desintegración radiactiva, el efecto fotoeléctrico, la radiación de fondo cósmica, el ruido atmosférico (que usaremos en este artículo) y más.

Por tanto, los números aleatorios generados basándose en dicha aleatoriedad se denominan números aleatorios "verdaderos".

Técnicamente, la parte del hardware consiste de un dispositivo que convierte la energía de una forma a otra (por ejemplo, radiación en una señal eléctrica), un amplificador y un convertidor de analógico a digital para convertir la salida en un número digital.

¿Qué son los números pseudoaleatorios?

image-146-opt
Imagen del código de computadora que fluye a través de la pantalla de la computadora. Foto por Markus Spiske.

Como alternativa a los números aleatorios "verdaderos", el segundo método para generar números aleatorios involucra algoritmos computacionales que pueden producir resultados aparentemente aleatorios.

¿Por qué aparentemente aleatorio? Porque los resultados finales obtenidos están, de hecho, completamente determinados por un valor inicial, también conocido como valor semilla o clave. Por lo tanto, si sabes el valor de la clave y cómo funciona el algoritmo, podría reproducir estos resultados aparentemente aleatorios.

Los generadores de números aleatorios de este tipo se denominan frecuentemente generadores de números pseudoaleatorios y, como resultado, generan números pseudoaleatorios.

Aunque este tipo de generador normalmente no recopila datos de fuentes de aleatoriedad natural, dicha recopilación de claves puede hacerse posible cuando sea necesario.

Comparemos algunos aspectos de los generadores de números aleatorios verdaderos o TRNG y los generadores de números pseudoaleatorios o PRNG.

Los PRNG son más rápidos que los TRNG. Debido a su naturaleza determinista, son útiles cuando necesita reproducir una secuencia de eventos aleatorios. Esto ayuda mucho en las pruebas de código, por ejemplo.

Por otro lado, los TRNG no son periódicos y funcionan mejor en funciones sensibles a la seguridad, como el cifrado.

Un período es el número de iteraciones por las que pasa un PRNG antes de que comience a repetirse. Por lo tanto, en igualdad de condiciones, un PRNG con un período más largo requeriría más recursos de la computadora para predecir y descifrar.

Ejemplo de algoritmo para el generador de números pseudoaleatorios

Una computadora ejecuta código que se basa en un conjunto de reglas a seguir. Para los PRNG en general, esas reglas giran en torno a lo siguiente:

  1. Acepta algún número de entrada inicial, que es una semilla o clave.
  2. Aplica esa semilla en una secuencia de operaciones matemáticas para generar el resultado. Ese resultado es el número aleatorio.
  3. Usa ese número aleatorio resultante como semilla para la siguiente iteración.
  4. Repite el proceso para emular la aleatoriedad.

Ahora vamos a ver un ejemplo.

El generador congruencial lineal

Este generador produce una serie de números pseudoaleatorios. Con una semilla inicial X0 y parámetros enteros a como multiplicador, b como incremento y m como módulo, el generador se define por la relación lineal: Xn ≡ (aXn-1 + b)mod m. O usando una sintaxis más amigable con la programación: Xn = (a * Xn-1 + b) % m.

Cada uno de estos miembros debe satisfacer las siguientes condiciones:

  • m > 0 (el módulo es positivo),
  • 0 < a < m (el multiplicador es positivo pero menor que el módulo),
  • 0 b < m (el incremento no es negativo, pero es menor que el módulo), y
  • 0 X0 < m (la semilla no es negativa, pero es menor que el módulo).

Vamos a crear una función de JavaScript que tome los valores iniciales como argumentos y devuelva un arreglo de números aleatorios de una longitud dada:


    // x0=semilla; a=multiplicador; b=incremento; m=módulo; n=longitud deseada de el arreglo;
	const generadorAleatorioLineal = (x0, a, b, m, n) => {
        const resultados = []
        for (let i = 0; i < n; i++) {
        	x0 = (a * x0 + b) % m
            resultados.push(x0)
        }
        return resultados
    }
	

El generador congruencial lineal es uno de los algoritmos PRNG más antiguos y conocidos.

En cuanto a los algoritmos generadores de números aleatorios que son ejecutables por computadoras, datan de las décadas de 1940 y 1950 (el método del cuadrado medio y el generador Lehmer, por ejemplo) y continúan escribiéndose hoy (Xoroshiro128+, Squares RNG y más).

Ejemplo de un generador de números aleatorios

Cuando decidí escribir este artículo sobre la incorporación de un generador de números aleatorios en una página web, tenía que tomar una decisión.

Podría haber usado la función Math.random() de JavaScript como base y generar resultados en números pseudoaleatorios como lo hice en artículos anteriores.

Pero este artículo en sí trata sobre la generación de números aleatorios. Así que decidí aprender a recopilar datos basados en la aleatoriedad "verdadera" y compartir mi descubrimiento con ustedes.

El código obtiene datos de una API, cortesía de Random.org. Este recurso en línea tiene una gran cantidad de herramientas útiles y personalizables y viene con una excelente documentación para acompañarlo.

La aleatoriedad proviene del ruido atmosférico. Pude usar funciones asincrónicas. Eso es un gran beneficio en el futuro. La función central se ve así:

// Genera un número aleatorio dentro del intervalo indicado por el usuario
const obtenerAleatorio = async (min, max, base) => {
   		const respuesta = await 	fetch("https://www.random.org/integers/?num=1&min="+min+"
    &max="+max+"&col=1&base="+base+"&format=plain&rnd=new")
          	return respuesta.text() 
   	} 

Los parámetros que toma permiten al usuario personalizar la salida de números aleatorios. Por ejemplo, min y max le permiten establecer límites inferiores y superiores en la salida generada. Y la base determina si la salida se imprime como binario, decimal o hexadecimal.

Nuevamente, elegí esta configuración, pero hay muchas más disponibles en la fuente.

Al hacer clic en el botón Generar, se llama a la función manejarGenerar(). A la vez, invoca la función asíncrona obtenerAleatorio(), gestiona el manejo de errores y genera resultados:


    // Gestión de salida
    const manejarGenerar = () => {
    	handleActive(generateButton)
        const base = binary.checked ? 2 : decimal.checked ? 10 : 16
        if (!minimum.value || !maximum.value) {
            prompter.style.color = 'red' 
        	prompter.textContent = "Ingrese valores mínimos y máximos"
        } else {
        	obtenerAleatorio(minimum.value, maximum.value, base).then((data) => {
        		resultValue.textContent = data
        		prompter.textContent = ""    
        	}).catch((error) => {
        		resultValue.textContent = 'ERROR'
        		prompter.textContent = 'Error de conexión. Incapaz de generar';    
        	})
       		 handleRestart()
        }
        
   }
    

El resto del código se ocupa de la estructura, la apariencia y el estilo de HTML.

El código está listo para ser incrustado y utilizado dentro de esta página web. Lo separé en partes y lo proporcioné con comentarios detallados. Se puede modificar fácilmente. También puede modificar la funcionalidad y los estilos según lo requieran sus necesidades.

Este es el enlace al repositorio de GitHub del código completo: https://github.com/sandroarobeli/random-generator