01 · Punto de partida
El ojo no alcanza
Hasta aquí generaste uniformes, enteros, sorteos y muestras. Todo parecía andar… hasta que una simulación da siempre lo mismo, un dado virtual favorece al 6 o dos réplicas “independientes” salen calcadas. El problema rara vez es tu fórmula de escala: es la secuencia base que fallaba en silencio.
Este tema abre el bloque de calidad (Temas 26–34): qué mirar antes de creerle a un generador y cómo decidir si vale una prueba formal o el reemplazo directo. Incluye el caso más famoso de la historia: RANDU, el generador de IBM que arruinó miles de simulaciones en los 60.
- ¿Qué tres propiedades resumen la calidad?
- ¿Qué señales baratas delatan un mal generador?
- ¿Por qué RANDU pasaba tests simples y fallaba en 3D?
- ¿Cuándo auditar y cuándo cambiar directo?
02 · Definición
Las tres patas del banco
Uniformidad
Cada subintervalo recibe su parte: media ≈ 0,5, varianza ≈ 1/12. Se testea contando (Temas 27, 29).
Independencia
El pasado no predice el futuro: correlación lag-1 ≈ 0, sin rachas raras ni planos. Se testea en pares (Temas 28, 30, 32).
Período
Mucho mayor que tu consumo: si pedís N valores, el período debe ser » N² por seguridad. Corto = repetición (Tema 33).
| Pata | Alarma barata | Test formal |
|---|---|---|
| Uniformidad | Media / histograma torcido | Chi-cuadrado, frecuencia (Temas 27, 29) |
| Independencia | Rachas, corr lag-1, gráfico (uₙ,uₙ₊₁) | Series, correlación, gráficos (Temas 28, 30–32) |
| Período | Se repite con N chico | Análisis de ciclo (Temas 10, 33) |
03 · Señales de alarma
El chequeo de 5 minutos
Antes de correr BigCrush, cinco números te dicen si vale la pena seguir: media, varianza, mínimo/máximo, correlación lag-1 y distintos en N. Un generador sano en [0,1) da 0,5 · 0,0833 · [0,1) · ≈0 · N.
- RANDU (IBM, 60s)
x = 65539·x mod 2³¹: parecía rápido y pasaba tests 1D, pero sus ternas caen en 15 planos paralelos. Moraleja: un test solo no certifica.- Período juguete
- LCG m = 16 con N = 1000 repite 60 veces el ciclo: la “uniformidad” es la del ciclo, no la del azar. Regla: período ≥ 100× tu N como mínimo.
- Correlación visible
- Si
uₙ₊₁ ≈ a·uₙ mod 1a ojo (diagonales en el gráfico de pares), el generador es predecible: clonalo con 2–3 datos (Tema 18).
Sano
Ruido honesto
Media 0,5 ±, varianza 0,083 ±, corr ≈ 0, N distintos. Pasa el ojo y merece tests formales.
Enfermo
Sesgo estructural
Media corrida, varianza chica/grande, corr ≠ 0 o ciclo corto: no se “compensa” con más N, se reemplaza el generador.
04 · Ejemplos
Tres enfermos clásicos
- 1LCG m = 16.
Falla por período: con N = 100 solo hay 16 valores. La media “cierra” pero la secuencia es un disco rayado.
- 2RANDU.
Falla por independencia en 3D: pares bien, ternas en 15 planos. Millones de papers de la época quedaron sesgados.
- 3
%sin rechazo.Falla por uniformidad inducida: el generador es sano pero el mapeo (Tema 22) vicia 4 caras. Se cura sin cambiar de generador.
05 · Implementación en Python
Auditor de 5 minutos
Una función que devuelve media, varianza, correlación lag-1 y distintos. Probala con random (sano) y con el juguete m = 16 (enfermo).
Python en tu navegador. Cambiá N a 200 y mirá cómo el sano se estabiliza y el juguete no mejora.
import random
import statistics
def auditar(us):
media = statistics.mean(us)
var = statistics.pvariance(us)
n = len(us)
m = statistics.mean(us)
cov = sum((us[i] - m) * (us[i + 1] - m) for i in range(n - 1)) / (n - 1)
corr = cov / var if var else 0.0
return media, var, corr, len(set(us))
rng = random.Random(26)
sano = [rng.random() for _ in range(2000)]
print("sano:", [round(v, 4) for v in auditar(sano)])
Sano ≈ (0,5 · 0,0833 · ≈0 · 2000): el patrón contra el que comparar todo.
El juguete enfermo
import statistics
def auditar(us):
media = statistics.mean(us)
var = statistics.pvariance(us)
n = len(us)
cov = sum((us[i] - media) * (us[i + 1] - media) for i in range(n - 1)) / (n - 1)
return media, var, cov / var if var else 0.0, len(set(us))
x = 7
mal = []
for _ in range(2000):
x = (5 * x + 3) % 16
mal.append(x / 16)
print("juguete:", [round(v, 4) for v in auditar(mal)])
06 · Exploración
Laboratorio: sano frente a enfermos
Tres fuentes con la misma escala [0,1): sano (mulberry32), juguete m = 16 y RANDU (65539·x mod 2³¹). La curva es u(n); el panel trae la auditoría. Subí N: el sano converge, los enfermos se delatan.
Auditoría visual
media 0,5 · var 1/12 · corr 0
Sano con N = 200: ruido honesto alrededor de los teóricos.
RANDU engaña en 1D (media y varianza dignas): su enfermedad vive en pares y ternas, Temas 30–32.
Preguntas para explorar
- Con N = 1000 en el juguete: ¿cuántos distintos hay? ¿Qué dice del período?
- Compará corr lag-1 del sano y del juguete: ¿cuál se aleja de 0 sistemáticamente?
- Si RANDU da media 0,5, ¿por qué igual desconfiamos? ¿Qué prueba lo atraparía?
Ver respuestas sugeridas
- 16: período juguete, N lo multiplica 60 veces. La “muestra” es el ciclo repetido.
- El juguete muestra corr positiva estable; el sano oscila ≈ 0 y se achica con N.
- Porque la enfermedad es multidimensional: la prueba de series/planos (Temas 30, 32) y el gráfico 3D lo delatan.
07 · Comprensión
Confusiones frecuentes
«A ojo se ve parejo, alcanza»
RANDU se veía parejo en histogramas 1D y era un desastre en 3D. El ojo no ve correlación lag-5 ni planos: los tests sí.
«Media 0,5 = generador bueno»
Necesario pero no suficiente: secuencia 0,1,0,9,0,1,0,9… da media 0,5 y es una calamidad. Faltan varianza e independencia.
«Un test que pasa certifica»
Cada test mira una pata: chi-cuadrado no ve orden, rachas no ven media. Calidad = batería, no medalla única.
«Más período siempre es mejor»
Período gigante con mala estructura (RANDU tenía 2²⁹) sigue siendo malo. Período es condición necesaria, no calidad total.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: el patrón 0,1/0,9
Mostrá que media 0,5 no certifica: auditá la secuencia alternada y compará con random.
import random
import statistics
def resumen(us):
return round(statistics.mean(us), 4), round(statistics.pvariance(us), 4)
alt = [0.1, 0.9] * 1000
rng = random.Random(2)
ref = [rng.random() for _ in range(2000)]
print("alternada:", resumen(alt))
print("random :", resumen(ref))
Ver solución razonada
Ambas dan media 0,5, pero varianzas 0,16 frente a 0,083: la alternada está “pasada de rosca”. Y su corr lag-1 ≈ −1 la remata.
Ejercicio 2: corr que delata
Calculá la correlación lag-1 de la alternada y de random. ¿Cuál denuncia dependencia total?
import random
def corr1(us):
m = sum(us) / len(us)
var = sum((u - m) ** 2 for u in us) / len(us)
cov = sum((us[i] - m) * (us[i + 1] - m) for i in range(len(us) - 1)) / (len(us) - 1)
return round(cov / var, 4)
print("alt:", corr1([0.1, 0.9] * 1000))
rng = random.Random(2)
print("rnd:", corr1([rng.random() for _ in range(2000)]))
Ver solución
alt ≈ −1,0 (zigzag perfecto), rnd ≈ 0,0 ± 0,03. Una sola cifra separa dependencia total de ruido honesto.
Ejercicio 3: RANDU en 1D se esconde
Auditá RANDU con N = 2000 en media/var: ¿pasa? ¿Qué prueba pedirías después?
Ver una posible respuesta
import statistics
x = 1
us = []
for _ in range(2000):
x = (65539 * x) % 2147483648
us.append(x / 2147483648)
print(round(statistics.mean(us), 4), round(statistics.pvariance(us), 4))
Media ≈ 0,5 y var ≈ 0,083: pasa el 1D. Pedir series/pares y gráfico 3D (Temas 30–32): ahí cae en 15 planos.
09 · Síntesis
Ideas para recordar
- Calidad = uniformidad + independencia + período » N.
- Auditor rápido: media 0,5, var 1/12, corr lag-1 ≈ 0, N distintos, min/max en [0,1).
- RANDU: 1D digno, 3D desastroso; un test no certifica.
- Sesgo estructural no se diluye con N: se reemplaza el generador o el mapeo.
- Este tema decide; los Temas 27–32 miden.
En el próximo tema medimos la primera pata: pruebas de uniformidad con chi-cuadrado.