Números Pseudoaleatorios · Tema 11

Historia de los generadores pseudoaleatorios

De tablas impresas y dados a Mersenne Twister: qué inventos sobrevivieron, qué desastres enseñaron y por qué hoy no se improvisa un generador.

01 · Punto de partida

Por qué mirar atrás antes de programar

En el Tema 10 mediste períodos en juguetes. La historia explica por qué esos juguetes existen y por qué los reales son como son: cada generador famoso nació de una necesidad (velocidad, período, memoria) y varios murieron por un defecto que hoy detectás en minutos.

Conocer dos fracasos —el middle-square que colapsa a cero y el RANDU que alineaba puntos en planos— te vacuna contra improvisar parámetros «que parecen andar».

  • ¿Cómo se generaba azar antes de las computadoras?
  • ¿Por qué el método de von Neumann colapsa?
  • ¿Qué fue RANDU y por qué es la advertencia del curso?
  • ¿Qué cambió con Mersenne Twister y los modernos?

02 · Línea de tiempo

De la tabla impresa al PCG en 70 años

◈

1927–1950: tablas y dados

Tippett (1927) y RAND (1947) publican tablas de dígitos; ENIAC tira dados reales. Lento, irrepetible, inmanejable para miles de valores.

⇄

1946–1949: middle-square y Lehmer

Von Neumann propone cuadrados medios (ingenioso, pero colapsa a 0). Lehmer (1948) crea el congruencial: rápido y analizable. Nace el LCG.

▣

1960–hoy: RANDU, tests y modernos

RANDU (60s) muestra el peligro de elegir mal a. Marsaglia (Diehard), L'Ecuyer (TestU01), MT (1997), xorshift (2003), PCG (2014).

Hitos que debes ubicar.
AñoHitoLección
1946Middle-square de von NeumannSimple no es sano: converge a 0
1948LCG de LehmerRápido y con teoría de período
1960sRANDU a=65539, m=2³¹Triplas caen en 15 planos: desastre espectral
1995–2007Diehard / TestU01Baterías que ningún serio evita
1997 / 2014MT / PCG, PhiloxPeríodo enorme + validación + velocidad

03 · Fracasos que enseñan

Dos autopsias obligatorias

Middle-square: muerte por cero
Tomá 4 dígitos, elevalos al cuadrado (8 dígitos), quedate con los 4 del medio. Si alguna vez sale 0000, queda en 0 para siempre; y hay muchas semillas que drenan a ciclos cortos. Von Neumann lo sabía: «quien use aritmética para azar peca», pero era lo único rápido en 1946.
RANDU: el desastre elegante
IBM eligió a = 65539 = 2¹⁶+3 por velocidad (shifts y sumas). En 1D parecía bien; en 3D las triplas (u(n),u(n+1),u(n+2)) caían en 15 planos paralelos. Simulaciones enteras de los 60–70 heredaron ese sesgo. Marsaglia lo inmortalizó: «los números caen en los planos».
Lección común
Ninguno se veía mal en media e histograma 1D. Hizo falta mirar pares, triplas y teoría espectral. Por eso los Temas 30–32 existen.

Error histórico

Elegir por velocidad

RANDU era rapidísimo y «pasaba» lo que se testeaba entonces. El costo lo pagaron miles de resultados.

Práctica actual

Elegir validado

Parámetros con teoría + batería (TestU01 BigCrush, PractRand) + código auditado. No se inventa un LCG casero para producir.

04 · Mapa

Qué quedó en pie

LCG→Combinados→MT / xorshift / PCG
  1. 1
    LCG bien parametrizado.

    Sigue vivo en didáctica y sistemas chicos: simple, rapidísimo, período conocido. Lo dominarás en los Temas 12–14.

  2. 2
    Combinados de L'Ecuyer.

    Mezclar dos LCG alarga el período y rompe estructuras. Puente al Tema 15.

  3. 3
    MT, xorshift, PCG, Philox.

    Períodos astronómicos, excelente uniformidad multidimensional y velocidad. El estándar para simular hoy (Tema 17).

05 · Autopsia en Python

Ver morir al middle-square

Con 4 dígitos lo ves colapsar en pocas iteraciones desde muchísimas semillas. Ningún LCG decente hace esto.

Python en tu navegador. Probá semillas 1234, 6789 y 1000: alguna muere en 0 rapidísimo.

def middle_square(semilla, n=12):
    x = semilla
    sal = []
    for _ in range(n):
        x = (x * x) % 100_000_000
        x = (x // 100) % 10_000
        sal.append(x)
    return sal


print(middle_square(1234))
print(middle_square(1000))

Verás ceros o ciclos de 1–2 valores: el generador «se traga» a sí mismo. Von Neumann lo usó por necesidad, no por bueno.

El LCG no muere así

def lcg(semilla, a=5, c=3, m=16, n=12):
    x = semilla
    sal = []
    for _ in range(n):
        x = (a * x + c) % m
        sal.append(x)
    return sal


print(lcg(7))

06 · Exploración

Laboratorio: museo de generadores

Elegí el generador y la semilla. El canvas muestra u(n) en orden (middle-square normalizado a /10000, LCGs a /m). Observá cuál se apaga y cuáles siguen vivos.

EXPERIMENTO 11

El que colapsa y los que resisten

middle-square vs. LCG

Los resultados numéricos aparecen debajo.
Último valor—
Distintos—
¿Colapsó a 0?—
Lectura—

Probá semilla 1000 en middle-square: muere pronto.

Línea que se aplana en cero = generador muerto. Líneas que siguen oscilando = ciclos vivos.

Preguntas para explorar

  1. Con middle-square y semilla 1000, ¿en cuántos pasos llega a 0? ¿Y con 1234?
  2. Con LCG bueno, ¿colapsa alguna semilla entre 1 y 15? ¿Y el malo cuántos distintos deja?
  3. Si en 1946 solo tenías middle-square, ¿qué precaución mínima tomarías?
Ver respuestas sugeridas
  1. 1000 muere en 1–2 pasos (1000² = 1000000 → medio 0000); 1234 agoniza en una decena con ciclos cortos.
  2. El bueno no colapsa: recorre el anillo. El malo deja ≤ 4 distintos: vivo pero inútil.
  3. Monitorear colapso, reiniciar con semilla fresca y jamás creerle a ciegas: la lección que llevó a Lehmer.

07 · Comprensión

Confusiones frecuentes

«Viejo = obsoleto, nuevo = bueno»

Un LCG bien elegido sigue siendo válido para usos simples; un «nuevo» sin tests puede ser peor que RANDU. Valen teoría + batería, no la fecha.

«Middle-square con buena semilla sirve»

No: el espacio está lleno de trampas que drenan a 0 o a ciclos de 1. Ninguna semilla lo hace confiable para N grande.

«RANDU era bueno porque lo usaba IBM»

La autoridad no certifica azar. RANDU pasó lo poco que se testeaba y falló lo que no se miraba (3D). Hoy no pasaría ni el primer filtro.

«La historia no afecta mi código»

Cada default que usás (random, NumPy) es una decisión histórica auditada. Entenderla te dice cuándo quedarte y cuándo migrar (Tema 17).

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: cazar el cero

Barre semillas 1–20 en middle-square de 4 dígitos y contá cuántas mueren en 0 antes de 20 pasos.

def muere(semilla, pasos=20):
    x = semilla
    for _ in range(pasos):
        x = (x * x) % 100_000_000
        x = (x // 100) % 10_000
        if x == 0:
            return True
    return False


print(sum(muere(s) for s in range(1, 21)), "de 20 mueren")
Ver solución razonada

Una fracción alta muere o cae en ciclos de 1–2: con 20 semillas ya ves el patrón. Ningún generador serio pierde así.

Ejercicio 2: ordenar la historia

Sin mirar: ordená middle-square, LCG de Lehmer, RANDU, Diehard/TestU01, Mersenne Twister, PCG. Luego verificá con la tabla del Tema.

orden = ["middle-square", "LCG Lehmer", "RANDU", "Diehard/TestU01", "MT", "PCG"]
print(" → ".join(orden))
Ver solución

1946 → 1948 → 60s → 1995/2007 → 1997 → 2014. Si dudas entre MT y TestU01, recordá: primero el problema (RANDU), luego el detector (baterías), luego el estándar (MT).

Ejercicio 3: tu criterio de adopción

Escribí una función que decida si adoptarías un generador «novedoso» según período declarado y tests pasados.

Ver una posible respuesta
def adoptar(periodo, tests_ok, teoria_ok):
    return periodo > 2**60 and tests_ok and teoria_ok


print(adoptar(2**32, True, False))
print(adoptar(2**128, True, True))

El primero se rechaza por falta de teoría aunque pase tests chicos; el segundo pasa el filtro inicial. Es el checklist mínimo antes de usar algo en producción.

09 · Síntesis

Ideas para recordar

  • Tablas → middle-square (colapsa) → LCG (rápido, analizable) → RANDU (desastre 3D) → baterías → MT/modernos.
  • Middle-square muere en 0; RANDU vive pero en 15 planos.
  • 1D no basta: la historia obligó a mirar pares, triplas y espectros.
  • No se adopta sin período demostrado + batería + teoría.
  • Tu default actual es historia auditada: úsalo con criterio, no por inercia.

En el próximo tema abrimos el motor que ganó: los generadores congruenciales lineales, su fórmula y su uso correcto.