01 · Punto de partida
Una línea que generó décadas de simulación
Después del museo del Tema 11, toca abrir el motor que ganó por simple y rápido: el generador congruencial lineal (GCL) de Lehmer. Una multiplicación, una suma y un resto. Con eso y una semilla produces millones de valores por segundo con teoría conocida.
Pero simple no es inocente: dos GCL con el mismo m y distinto a pueden ser uno excelente y otro desastroso (ya lo viste con 5,3 vs 4,2). Este tema enseña la mecánica; los Temas 13–14 enseñan la elección.
- ¿Qué significa cada letra de
(a·x + c) mod m? - ¿Qué diferencia hay entre mixto y multiplicativo?
- ¿Cómo se itera a mano sin perderse?
- ¿Cómo se implementa sin overflow ni sesgo?
02 · Definición
Anatomía de la receta
Multiplicador a
Mezcla el estado: a·x lo estira. Mal elegido deja ciclos cortos o estructuras en pares/triplas (RANDU).
Incremento c
Si c ≠ 0 es mixto; si c = 0 es multiplicativo (Lehmer). El c saca del cero y permite período completo.
Módulo m
El tamaño del anillo: el período nunca supera m. Potencia de 2 = rápido; primo de Mersenne = mejor estadística con más costo.
| Tipo | Condición | Período máx. | Ojo con |
|---|---|---|---|
| Mixto | c ≠ 0 | m | Elegir a, c con teorema (Tema 14) |
| Multiplicativo | c = 0 | m − 1 | Semilla 0 lo mata; x = 0 prohibido |
| Park–Miller | a=16807, m=2³¹−1 | m − 1 | Overflow en 32 bits si se multiplica directo |
03 · Paso a paso
Iterar a mano sin perderse
Con x₀=7, a=5, c=3, m=16:
- Paso 1
x₁ = (5·7+3) mod 16 = 38 mod 16 = 6→u₁ = 6/16 = 0,375.- Paso 2
x₂ = (5·6+3) mod 16 = 33 mod 16 = 1→u₂ = 0,0625.- Paso 3
x₃ = (5·1+3) mod 16 = 8→u₃ = 0,5. Ya ves saltos, no orden.- Regla
- Siempre multiplicar → sumar → resto → dividir. El resto es lo que dobla la recta en anillo.
Bien implementado
Enteros exactos
El mod se hace en enteros (Python int, C con 64 bits o Schrage). La división a [0,1) es lo último.
Mal implementado
Flotantes en el medio
Hacer (a*x+c)/m con flotantes y luego resto acumula error y rompe el ciclo teórico.
04 · Ejemplos
Tres GCL para calibrar
- 1Didáctico bueno.
(5,3,16,7): período 16, salta sin orden visible. Para aprender, no para producir. - 2Park–Miller mínimo.
(16807,0,2³¹−1): estándar histórico, período ~2·10⁹. Multiplicativo: semilla nunca 0. - 3RANDU (no usar).
(65539,0,2³¹): rápido y con triplas en 15 planos. El ejemplo de qué no elegir.
05 · Implementación en Python
Generador como iterador
Esta forma con yield separa estado de consumo y te servirá para todos los generadores del curso.
Python en tu navegador. Cambiá a a 4 y c a 2 para ver el colapso con el mismo código.
def gcl(semilla, a=5, c=3, m=16):
x = semilla
while True:
x = (a * x + c) % m
yield x / m
g = gcl(7)
print([round(next(g), 4) for _ in range(8)])
Ocho uniformes que cubren [0,1) sin orden obvio. Resembrar es crear otro gcl(otra_semilla).
Park–Miller en Python (sin overflow)
def park_miller(semilla, n=5):
a, m = 16807, 2**31 - 1
x = semilla
sal = []
for _ in range(n):
x = (a * x) % m
sal.append(round(x / m, 6))
return sal
print(park_miller(1))
06 · Exploración
Laboratorio: la receta bajo la lupa
Mové a, c, semilla y N con m = 16 fijo para ver la mecánica. El panel lista los primeros 6 x, el período y la media. La línea vertical marca el fin del primer ciclo.
Iterar el mod
x(n+1) = (a·x(n) + c) mod 16
Con (7,5,3) el período es 16.
Cada punto es u(n)=x(n)/16. Pasada la marca, el dibujo se repite: el mod cerró el anillo.
Preguntas para explorar
- Con (7,5,3), anotá los 6 primeros x a mano y compará con el panel. ¿Coinciden?
- Poné c = 0 con semilla 0: ¿qué pasa? ¿Y con semilla 7?
- Poné (7,4,2): ¿período? ¿Media «buena» igual? ¿Qué dice eso de juzgar por media?
Ver respuestas sugeridas
- Sí: 6, 1, 8, 11, 10, 5… El cálculo a mano es la mejor forma de fijar el orden multiplicar→sumar→resto.
- Con 0 queda en 0 para siempre; con 7 entra en un ciclo sin el 0. El multiplicativo expulsa al cero del anillo útil.
- Período ≤ 4 con media que puede dar 0,5 igual: la media no detecta el desastre.
07 · Comprensión
Confusiones frecuentes
«x y u son lo mismo»
x es entero en 0..m−1 (aritmética del ciclo); u = x/m es el uniforme que usa tu simulación. Mezclarlos rompe tests y transformaciones.
«Hago el mod con flotantes, da igual»
No: el ciclo teórico vive en enteros exactos. Flotantes intermedios meten redondeo y cambian la secuencia (Temas 39–40).
«Cualquier a impar sirve»
El período y la estructura 2D/3D dependen finamente de a. RANDU era impar y es el contraejemplo del curso.
«En Python no hay overflow, ignoro el tema»
En Python no, pero el GCL que portes a C/Java/simulador sí. Si elegís a·(m−1) mayor que 2³², tu port explota.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: iterar a mano y verificar
Calculá x₁, x₂, x₃ desde 7 con (5,3,16) a mano y verificá con código.
x = 7
for i in range(3):
x = (5 * x + 3) % 16
print(i + 1, x, round(x / 16, 4))
Ver solución razonada
6 → 0,375; 1 → 0,0625; 8 → 0,5. Si te dio otra cosa, revisá el orden: primero 5·x+3, después mod 16.
Ejercicio 2: mixto vs. multiplicativo desde 0
Compará ambos desde semilla 0 con el mismo a. ¿Cuál sobrevive?
def seq(s, a, c, m, n=6):
x = s
sal = []
for _ in range(n):
x = (a * x + c) % m
sal.append(x)
return sal
print(seq(0, 5, 3, 16))
print(seq(0, 5, 0, 16))
Ver solución
Mixto varía; multiplicativo queda en ceros. Por eso el multiplicativo exige semilla ≠ 0 y período ≤ m−1.
Ejercicio 3: bits bajos débiles
Con m potencia de 2, el bit menos significativo alterna con período ≤ 2. Observá la paridad de la secuencia.
Ver una posible respuesta
x = 7
par = []
for _ in range(10):
x = (5 * x + 3) % 16
par.append(x % 2)
print(par)
Verás alternancia o constancia: los bits bajos son los más débiles con m = 2ᵏ. Moraleja: nunca uses x mod 2 para decidir; usá los bits altos o la división completa (Tema 22).
09 · Síntesis
Ideas para recordar
- GCL:
x(n+1) = (a·x(n)+c) mod m, salidau = x/m. - Mixto (c≠0, p≤m) vs. multiplicativo (c=0, p≤m−1, semilla≠0).
- Orden: multiplicar → sumar → resto en enteros → dividir.
- Cuidado con overflow al portar y con bits bajos si m es potencia de 2.
- La mecánica es fácil; la elección de (a,c,m) es el arte (Temas 13–14).
En el próximo tema diseccionaremos cada parámetro de un generador congruencial: qué rompe cada uno cuando se elige mal.