Generación de números pseudoaleatorios con rand y srand

rand() es una función que devuelve un número entero que parece ser aleatorio, pero no lo es realmente; se le llama pseudoaleatorio. En lugar de medir el ruido atmosférico o fenómenos físicos, utiliza una fórmula matemática para generar una secuencia de números. Esta secuencia es determinista, lo que significa que si conoces la fórmula y el punto de inicio, puedes predecir exactamente qué números vendrán después. El valor máximo que puede devolver es RAND_MAX, una constante definida en stdlib.h que garantiza ser, como mínimo, 32767.

Para que el programa no devuelva siempre la misma secuencia cada vez que lo ejecutas, necesitamos una semilla (o seed). La semilla es el número inicial que la fórmula matemática usa para comenzar el cálculo. La función srand() es la encargada de establecer esta semilla. Si llamas a srand() con la misma semilla, obtendrás exactamente la misma secuencia de números. Por eso, lo más común es usar time(NULL) (de la librería <time.h>) como semilla, ya que devuelve el tiempo actual en segundos, asegurando que cada vez que ejecutes el programa, la semilla sea distinta.

Debes usar rand() para simulaciones sencillas, juegos no competitivos o cuando la velocidad sea más importante que la perfección del azar. Sin embargo, nunca debes usar rand() para tareas de seguridad, como generar contraseñas, tokens de sesión o claves de cifrado, ya que un atacante podría predecir los números fácilmente. Si lo usas mal, podrías obtener secuencias repetitivas que rompan la lógica de tu programa o, en el caso de la seguridad, dejar tu sistema vulnerable.

Para que el compilador entienda estas funciones, el compilador (como gcc) necesita saber cómo se llaman y qué reciben; esto se logra incluyendo las cabeceras stdlib.h y time.h. Luego, el enlazador (linker) busca la implementación real de estas funciones en las librerías del sistema para que el programa pueda ejecutarse.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    // Establecemos la semilla usando el tiempo actual para que 
    // los números cambien en cada ejecución del programa.
    srand((unsigned int)time(NULL));

    printf("Simulando el lanzamiento de un dado (1 al 6):\n");

    for (int i = 0; i < 10; i++) {
        // rand() devuelve un número entre 0 y RAND_MAX.
        // Usamos el operador módulo (%) para limitar el rango.
        // Sumamos 1 para que el rango sea de 1 a 6 en lugar de 0 a 5.
        int dado = (rand() % 6) + 1;
        printf("Lanzamiento %d: %d\n", i + 1, dado);
    }

    // Ejemplo de un número más grande
    int numero_grande = rand();
    printf("\nUn numero aleatorio cualquiera: %d\n", numero_grande);

    return 0;
}

Desglose del ejemplo

En el código anterior, la función srand((unsigned int)time(NULL)) es el corazón de la variedad. Sin esa línea, si ejecutaras el programa cinco veces, verías los mismos 10 números en las cinco ocasiones. El cast (unsigned int) se utiliza para evitar advertencias del compilador, ya que time() devuelve un tipo time_t y srand() espera un unsigned int.

Dentro del bucle for, la expresión (rand() % 6) + 1 es el truco estándar para limitar el rango. rand() nos da un número enorme (por ejemplo, 15432). Al aplicar % 6 (módulo), el resultado es el resto de dividir ese número entre 6, lo cual siempre será un valor entre 0 y 5. Al sumar 1, desplazamos ese rango para obtener un [1, 6], ideal para simular un dado.

Finalmente, la variable numero_grande recibe directamente el valor de rand(). Es importante notar que, dependiendo de tu sistema, RAND_MAX podría ser un valor pequeño como 32767 o un valor mucho más grande. Por eso, el comportamiento de rand() depende de la implementación de la librería estándar de C en tu sistema operativo.

El error frecuente

Un error clásico cuando se empieza con C es colocar la función srand() dentro de un bucle.

// ERROR: Semilla reiniciada constantemente
for (int i = 0; i < 5; i++) {
    srand((unsigned int)time(NULL)); 
    printf("%d\n", rand() % 100);
}

Como time(NULL) devuelve el tiempo en segundos, la CPU ejecutará este bucle tan rápido que el tiempo será el mismo para todas las iteraciones. Al llamar a srand() repetidamente con la misma semilla, reinicias el generador en el mismo punto de la secuencia, provocando que rand() devuelva siempre el mismo número en cada paso del bucle.

85

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio