Números Pseudoaleatorios · Tema 44

Calidad del generador y resultados

Un mal generador no hace ruido: hace sesgo. Más réplicas no lo curan, solo lo confirman.

01 · Punto de partida

Más datos no arreglan mal azar

Todo el curso desemboca acá: la simulación come uniformes U(0,1) y devuelve promedios, colas y decisiones. Si el generador es bueno (Temas 12–17) y pasó las pruebas (Temas 26–32), el error cae con 1/√N y más réplicas ayudan. Si es malo —período corto (Tema 33), correlación (Tema 32), enteros con % sesgado (Tema 35)—, el resultado converge… al valor equivocado. Y converge con confianza: el intervalo se achica alrededor del sesgo.

El caso famoso es RANDU (IBM, años 60): parecía rápido e inofensivo hasta que los puntos 3D cayeron en 15 planos. Tu Monte Carlo puede tener su RANDU casero si improvisás parámetros.

  • ¿Cómo distingo sesgo (sistemático) de ruido (estadístico)?
  • ¿Qué defectos del generador sesgan la media, la varianza y las colas?
  • ¿Por qué N grande no compensa un período corto?
  • ¿Qué chequeo mínimo hago antes de creer un resultado?

02 · Definición

Sesgo que no se promedia

◈

Sesgo

Desvío sistemático del valor real: media corrida, colas flacas, planos. Crece o se queda; nunca se promedia a cero.

⇄

Ruido √N

Dispersión honesta que cae ÷√10 cada ×10 réplicas. Es el error “bueno” que el intervalo cuantifica.

▣

Período y lattice

Con período P solo existen P tuplas: pasado P, repetís azar. Y los LCG viven en hiperplanos (RANDU = 15 planos en 3D).

Síntoma en el resultado, causa en el generador.
SíntomaCausa típicaTest que lo delata
π o media clavada fuera del realPeríodo corto / lattice gruesaSeries y gráfico 2D/3D (Temas 30–31)
Colas que no aparecen nuncaBits bajos débiles / % sesgadoFrecuencia y χ² (Temas 27, 29)
Rachas o alternancia raraCorrelación lag-1Independencia y runs (Tema 28)

03 · Anatomía

Los tres saboteadores

Todo sesgo de generador es uno de estos tres, o mezcla:

Período corto (hambre de tuplas)
Con módulo m solo hay m pares/triplas posibles: un Monte Carlo 3D con m = 2048 no explora el cubo, lo “pinta” con 2048 puntos. Más N solo repinta. (Tema 33.)
Correlación (memoria fantasma)
Sucesivos atados por la fórmula (x(n+1) = a·x(n)+c): el lag-1 ≠ 0 tuerce promedios de pares, caminatas y colas. Se mide con autocorrelación (Tema 32).
Mapeo sesgado (el % tramposo)
int(u*n) con % sobre rango no divisor de m, o u = x/m con redondeo al borde, carga unos valores más que otros. El histograma nace torcido (Tema 35).

Bien alimentado

Moderno + testeado

PCG/MT/Philox con período ≫ N, mapeo sin % (int(u*n) con tope), semilla registrada y χ² + runs en verde.

Mal alimentado

Casero improvisado

LCG con parámetros “lindos” (a=13, m=256), % n directo y sin tests: π clavado 0,1 fuera y colas que no existen.

04 · Ejemplos

Tres sesgos famosos

Defecto del G→Muestra torcida→Resultado sesgado
  1. 1
    RANDU y los 15 planos.

    x(n+1) = 65539·x(n) mod 2³¹: en 3D todos los puntos caen en 15 planos. Integrar un volumen con eso es medir los huecos, no el volumen.

  2. 2
    π con juguete m = 256.

    Solo 256 pares posibles: el π estimado se clava en un valor fijo (sesgado ~0,1) por más que subas N a 100 000. Laboratorio de abajo.

  3. 3
    Dado con % 6 sesgado.

    Con m = 2³² no divisible por 6, dos caras salen un tick más: en 1 M de tiros el χ² explota aunque “parezca” parejo a ojo.

05 · Demostración en Python

π bueno frente a π de juguete

El mismo Monte Carlo, dos fuentes: random (moderno) y un LCG de juguete m = 256. Uno converge a π; el otro a su lattice.

Python en tu navegador. Subí N a 20 000: el bueno se pega a 3,14 y el juguete ni se mueve de su sesgo.

import math
import random

def lcg_juguete(n, semilla=1, a=13, c=7, m=256):
    x = semilla % m
    for _ in range(n):
        x = (a * x + c) % m
        yield x / m

def pi_con(gen, n):
    dentro = 0
    it = iter(gen)
    for _ in range(n):
        x, y = next(it), next(it)
        dentro += x * x + y * y < 1
    return 4 * dentro / n


N = 5000
random.seed(44)
bueno = pi_con((random.random() for _ in range(2 * N)), N)
malo = pi_con(lcg_juguete(2 * N), N)
print("bueno:", round(bueno, 4), "malo:", round(malo, 4), "real:", round(math.pi, 4))

Bueno ≈ 3,14 ± 0,03; juguete clavado lejos (típico ~2,9–3,3 según semilla): el sesgo no baja con N.

El test de 2 líneas que lo hubiera delatado

vals = list(lcg_juguete(2000))
print("únicos:", len(set(vals)), "de 2000")
print("media:", round(sum(vals) / len(vals), 4))

06 · Exploración

Laboratorio: π con buen y mal generador

El mismo cuarto de círculo, dos lluvias de puntos: la verde usa un LCG serio (1664525/2³²) y la naranja el juguete (m = 256). Movete en N: la verde se pega a π; la naranja se clava en su lattice y deja de aprender.

EXPERIMENTO 44

π(N): converge o se clava

π ≈ 4 · dentro / N

Los resultados numéricos aparecen debajo.
π bueno—
π malo—
Sesgo malo—
Veredicto—

Con N = 2000 el bueno roza π y el malo sigue en su lattice.

El eje x es N (pares); el eje y es el π estimado. La punteada es π real. La naranja se aplana lejos: más N no la mueve.

Preguntas para explorar

  1. Con N = 200: ¿se distinguen? ¿Y con N = 8000?
  2. Con N = 8000 (≫ período 256 del malo): ¿por qué la naranja no mejora aunque cuadrupliques N?
  3. Si dos semillas del generador bueno dan π distintos pero cercanos, ¿sesgo o ruido? ¿Y si el malo repite idéntico?
Ver respuestas sugeridas
  1. Con N chico ambas botan (ruido domina); con N grande la verde se pega a π y la naranja queda clavada: el sesgo sobrevive al ruido.
  2. Porque solo existen 256 pares: pasado 256 repite puntos. N grande repinta la misma lattice: el error es sistemático, no muestral.
  3. Dispersión entre semillas buenas = ruido √N (sano); repetición idéntica del malo = período agotado. El test de “otra semilla” separa ambos.

07 · Comprensión

Confusiones frecuentes

«Con N = 10 M todo generador sirve»

Al revés: N gigante exige período ≫ N. Si N supera al período, el “azar” es un loop: más réplicas solo confirman el sesgo con más decimales.

«Si la media da 0,5, el generador está bien»

Media 0,5 es necesaria pero no suficiente: RANDU daba media perfecta y fallaba en 3D. Faltan χ², runs y pares/ternas (Temas 27–31).

«El intervalo de confianza me protege del sesgo»

El intervalo cuantifica ruido, no sesgo: con mal generador se achica alrededor del valor equivocado. Falsa precisión.

«Cambiar la semilla arregla un mal generador»

Cambia el dibujo del sesgo, no el sesgo: otra ventana del mismo lattice. Se arregla cambiando de familia/parámetros, no de semilla.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: contar el período

Mostrá que el juguete tiene 256 valores únicos aunque le pidas 2000.

def lcg(n, semilla=1, a=13, c=7, m=256):
    x = semilla % m
    for _ in range(n):
        x = (a * x + c) % m
        yield x / m


vals = list(lcg(2000))
print(len(set(vals)), "únicos de 2000")
Ver solución razonada

256 únicos: el ciclo se cierra y todo lo demás es repetición. Un π con N = 8000 usa cada par ~30 veces: no estima, recita.

Ejercicio 2: el sesgo no baja con N

Compará el error |π − real| del bueno y del malo con N = 1000 y N = 8000.

import math
import random

def pi_pares(pares):
    dentro = sum(1 for x, y in pares if x * x + y * y < 1)
    return 4 * dentro / len(pares)


random.seed(44)
for n in [1000, 8000]:
    buenos = [(random.random(), random.random()) for _ in range(n)]
    print(n, abs(pi_pares(buenos) - math.pi))
Ver solución

El bueno achica su error ~÷√8 al ×8 N; el malo mantiene su sesgo (~0,05–0,2) intacto. Esa es la firma: el error que no escala con 1/√N es sesgo.

Ejercicio 3: otra semilla, mismo sesgo

Repetí el π de juguete con semillas 1 y 2: ¿cambia el veredicto “lejos de π”?

Ver una posible respuesta
def pi_juguete(n, semilla):
    x = semilla % 256
    dentro = 0
    for _ in range(n):
        x = (13 * x + 7) % 256
        px = x / 256
        x = (13 * x + 7) % 256
        py = x / 256
        dentro += px * px + py * py < 1
    return 4 * dentro / n


print(pi_juguete(5000, 1), pi_juguete(5000, 2))

Ambos lejos de π (distinto dibujo, mismo sesgo): cambiar semilla mueve la lattice, no la rompe. La cura es otra familia (Tema 17).

09 · Síntesis

Ideas para recordar

  • Error = sesgo (no baja con N) + ruido/√N (sí baja).
  • Nunca N > período: el azar se vuelve loop.
  • Media 0,5 no alcanza: χ² + runs + pares/ternas.
  • El intervalo mide ruido, no sesgo: puede ser falsamente preciso.
  • Otra semilla ≠ otro generador: el sesgo se cambia de familia, no de semilla.

En el próximo y último tema ponemos todo a trabajar: un proyecto evaluador completo de un generador en Python.