Números Pseudoaleatorios · Tema 04

Secuencias pseudoaleatorias

Qué es una secuencia generada por recurrencia, por qué el orden importa más que los valores sueltos y cómo leer semilla, estado y período en tus primeros generadores.

01 · Punto de partida

Del número suelto a la secuencia

Hasta ahora hablaste de «números aleatorios» en singular: un dado, un random.random(). Pero un simulador nunca usa uno solo: usa una secuencia ordenada u₀, u₁, u₂, …, donde cada posición alimenta un sorteo, un tiempo de llegada o una decisión.

Y ahí cambia la exigencia: no alcanza con que cada valor «parezca azar» por separado; la sucesión completa debe comportarse como azar: sin ciclos visibles, sin correlación entre vecinos y reproducible desde la semilla. Esa sucesión calculada es la secuencia pseudoaleatoria.

  • ¿Qué distingue una secuencia de una simple colección de valores?
  • ¿Cómo se genera el siguiente valor solo desde el actual?
  • ¿Por qué toda secuencia calculada termina repitiéndose?
  • ¿Cómo la explorás con código antes de confiar en ella?

02 · Definición

Recurrencia, estado y salida

Toda secuencia del curso nace del mismo mecanismo, que conviene nombrar con precisión desde ahora:

◈

Recurrencia

La regla que calcula lo nuevo desde lo actual. Ejemplo didáctico: x(n+1) = (5·x(n) + 3) mod 16. Sin recurrencia no hay generador.

⇄

Estado y semilla

El estado es lo que el generador recuerda (x(n)); la semilla es el estado inicial x₀. Mismo x₀, misma historia completa.

▣

Salida normalizada

El valor usable u(n) = x(n) / m en [0,1). Es lo que graficarás, contarás y transformarás en los Temas 19–25.

Dos consecuencias inmediatas: (1) la secuencia es determinista y reproducible; (2) como el estado tiene finitos valores posibles (el módulo m), tarde o temprano un estado se repite y desde ahí todo el ciclo se repite. Ese es el período (Tema 10).

Vocabulario de secuencia con un ejemplo chico.
TérminoEjemplo con m = 16Qué significa
Semillax₀ = 7Punto de partida elegido por vos
Recurrencia(5·x + 3) mod 16Cómo avanza cada paso
Estado7 → 6 → 1 → …Enteros internos que se encadenan
Salida7/16, 6/16, 1/16, …Uniformes en [0,1) que usa tu simulación

03 · Lectura

Cómo leer una secuencia sin autoengañarte

Una secuencia se lee en orden y en conjunto. Estos tres hábitos te evitan la mayoría de los errores de principiante:

Orden
Los pares consecutivos importan: (u₀,u₁), (u₁,u₂), … revelan correlaciones que los valores sueltos esconden. Los tests de series (Tema 30) miran justamente eso.
Ventana
Mirá tramos cortos y largos: un generador puede verse bien en 100 valores y colapsar en 10 000 por período corto (Tema 33).
Repetición
Buscá el primer estado repetido: desde ahí la secuencia es un loop. Con módulo chico lo ves a ojo; con módulo grande necesitás código.
Normalización
No compares enteros x con uniformes u: dividí por m antes de graficar o contar frecuencias (Temas 19–20).

Buena lectura

Secuencia como historia

Graficás en orden, contás por intervalos, medís vecinos y registrás semilla y parámetros junto a cada gráfico.

Mala lectura

Valores sueltos

Mirás el promedio de 20 valores y declarás «es aleatorio». El promedio esconde ciclos, bandas y correlaciones.

04 · Ejemplos

Tres secuencias para calibrar el ojo

Antes del laboratorio, tres casos mentales que anticipan todo el curso:

Semilla→Recurrencia→Secuencia u(n)
  1. 1
    Secuencia constante.

    0,5, 0,5, 0,5, … Tiene promedio perfecto 0,5 y es una pésima secuencia: cero variabilidad, período 1.

  2. 2
    Secuencia alternada.

    0, 1, 0, 1, … Parece «equilibrada» pero la correlación entre vecinos es total: sabiendo uno, sabés el siguiente.

  3. 3
    LCG didáctico.

    x(n+1) = (5·x(n)+3) mod 16 desde x₀=7: enteros que saltan y uniformes que cubren [0,1) sin orden obvio. Es el que explorarás abajo.

05 · Generación en Python

Tu primer generador escrito a mano

Nada de caja negra: este LCG de juguete cabe en 6 líneas y te deja ver semilla, transición y salida. Con módulo 16 podés seguirlo paso a paso; con módulos reales (millones) haría lo mismo pero ilegible.

Python en tu navegador. Cambiá la semilla y los parámetros y observá cómo cambia la historia completa, no solo un valor.

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


ent, uni = lcg(7)
print("x:", ent)
print("u:", [round(v, 4) for v in uni])

Ejecutalo con semilla 7 y luego con semilla 8: las dos historias difieren desde el primer paso. Eso es sensibilidad a la semilla.

Detectar el período a mano

¿Cuántos valores distintos salen antes de que el estado se repita? Este detector te da el período empírico, anticipo del Tema 10:

def periodo(semilla, a=5, c=3, m=16):
    visto = {}
    x = semilla
    i = 0
    while x not in visto:
        visto[x] = i
        x = (a * x + c) % m
        i += 1
        if i > m + 2:
            break
    return i - visto[x], x


print(periodo(7))

06 · Exploración

Laboratorio: explorador de secuencias

Mové semilla, parámetros y cantidad de valores. La curva muestra u(n) en orden; el panel informa el período empírico detectado. Con módulo 16 verás ciclos cortos a simple vista: esa es la lección.

EXPERIMENTO 04

Recurrencia visible

x(n+1) = (a·x(n) + c) mod m

Los resultados numéricos aparecen debajo.
Período empírico—
Estados distintos en N—
Primer u—
Lectura—

Probá a = 4, c = 2: el período se derrumba.

Cada punto es u(n) = x(n)/m en orden de generación. Si N supera al período, verás el ciclo repetirse calcado.

Preguntas para explorar

  1. Con el ejemplo (7, 5, 3, 16) y N = 48, ¿se repite el dibujo? ¿Cada cuántos puntos?
  2. Poné a = 4, c = 2, m = 16. ¿Cuántos valores distintos quedan? ¿Qué le haría eso a una simulación?
  3. Cambiá solo la semilla de 7 a 8 con buenos parámetros: ¿cambia el período o solo el punto de arranque del ciclo?
Ver respuestas sugeridas
  1. Sí: con buenos parámetros el período es 16 y con N = 48 ves 3 ciclos idénticos. El ojo detecta la repetición calcada.
  2. Colapsa a un ciclo de 4 o menos: tu «azar» tendría solo 4 valores. Cualquier promedio o histograma saldría sesgado.
  3. Solo el arranque: el ciclo es el mismo anillo, entrás por otra puerta. El período lo mandan a, c, m, no la semilla (Tema 14).

07 · Comprensión

Confusiones frecuentes

«Si cada valor parece uniforme, la secuencia es buena»

No: la alternancia 0, 1, 0, 1… tiene promedio 0,5 perfecto y es inútil. La calidad está en el orden: vecinos, pares y ciclos.

«Cambiar la semilla alarga el período»

La semilla elige dónde entrás al ciclo, no su largo. El período máximo lo deciden a, c, m. Con malos parámetros, ninguna semilla te salva.

«Con N chico ya puedo juzgar»

Con N menor que el período todo parece nuevo. Pedí siempre N varias veces mayor que el período sospechado para ver la repetición.

«Los enteros x y los uniformes u son lo mismo»

Están relacionados por u = x / m, pero se analizan distinto: los tests de frecuencia usan intervalos de u; la aritmética del período vive en x.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: generar y graficar con texto

Generá 16 valores con el LCG del ejemplo e imprimí enteros y uniformes lado a lado. Buscá a ojo el momento en que el estado inicial reaparece.

def lcg(semilla, a=5, c=3, m=16, n=16):
    x = semilla
    for i in range(n):
        x = (a * x + c) % m
        print(i, x, round(x / m, 4))
Ver solución razonada

Llamá lcg(7): verás 16 estados distintos antes de volver a un repetido. Ese «volver» es el cierre del ciclo. Con N = 20 verías los primeros 4 valores repetidos al final.

Ejercicio 2: comparar dos semillas

Generá la secuencia desde 7 y desde 8 con los mismos parámetros. ¿Son distintas secuencias o el mismo anillo rotado?

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


s7 = secuencia(7)
s8 = secuencia(8)
print(s7)
print(s8)
print("comparten valores:", set(s7) == set(s8))
Ver solución

Con buenos parámetros ambos conjuntos coinciden: es el mismo ciclo empezado en otro punto. Con malos parámetros pueden caer en ciclos disjuntos: otra señal de generador pobre.

Ejercicio 3: romper el generador

Probá a=4, c=2, m=16 desde varias semillas y medí el período con la función del Tema 4. ¿Qué período máximo lográs?

Ver una posible respuesta
def periodo(semilla, a, c, m):
    visto = {}
    x = semilla
    i = 0
    while x not in visto:
        visto[x] = i
        x = (a * x + c) % m
        i += 1
    return i - visto[x]


for s in [0, 1, 7, 12]:
    print(s, periodo(s, 4, 2, 16))

Períodos de 4 o menos: el generador solo visita una fracción del módulo. Es el ejemplo mínimo de por qué los parámetros se estudian con teoría (Temas 13–14) y no a ojo.

09 · Síntesis

Ideas para recordar

  • Secuencia = lista ordenada por recurrencia desde una semilla; el orden es evaluable.
  • Estado, transición y salida u = x / m describen cualquier generador.
  • Toda secuencia calculada es eventualmente periódica: el estado finito obliga al ciclo.
  • La semilla elige el arranque, no el largo del ciclo; los parámetros sí.
  • Documentá siempre (semilla, a, c, m, n) junto a cada secuencia.

En el próximo tema nos concentraremos en la pieza que elige la historia: las semillas, cómo elegirlas, registrarlas y no arruinar tu experimento con ellas.