Generacion de numeros aleatorios en C

En C, podemos generar números aleatorios con una función incluida en la librería stdlib.h

Sin embargo estos numeros generados no son tan aleatorios como podriamos creer en un principio.

Si generamos varios numeros aleatorios en un programa en C, como en el siguiente ejemplo, con la función rand(), cada vez que llamamos a la funcion se genera un nuevo numero aleatorio. De la siguiente forma obtenemos la sucesion de numeros; 41, 18467, 6334, ...

              #include <stdio.h> //incluye la libreria de donde importamos la funcion printf()
              #include <stdlib.h> //incluye la libreria de donde importamos la funcion  rand()
              void main() {
                  int i, num;
                  for (i=0; i<5; i++){
                      printf("%d, ", rand());
                  }
              }
              
                41, 18467, 6334, 26500, 19169, .....
              

Sin embargo si cerramos el programa y o volvemos a ejecutar, obtendremos la siguiente sucesion de numeros; 41, 18467, 6334, ... Esto sucede porque la funcion rand(), no genera numeros aleatorios, sino, pseudo-aleatorios. La funcion depende de una semilla, que generará la sucesion de numeros aleatorios. La funcion srand() recibe como argumento, un numero entero, que tendrá el valor de la nueva semilla. Nuestro código quedará de la siguiente manera.

              #include <stdio.h> //incluye la libreria de donde importamos la funcion printf()
              #include <stdlib.h> //incluye la libreria de donde importamos la funcion rand() y srand()
              void main() {
                  int i, seed;
                  printf("Semilla por default\n");
                  for (i=0; i<5; i++){
                      printf("%d, ", rand());
                  }
  
                  for (seed=0; seed<5; seed++){
                      printf("\nValor de semilla igual a %d\n", seed);
                      srand(seed);
                      for (i=0; i<5; i++){
                          printf("%d, ", rand());
                      }
                  }
              }
              
                Semilla por default
                41, 18467, 6334, 26500, 19169,
                Valor de semilla igual a 0
                38, 7719, 21238, 2437, 8855,
                Valor de semilla igual a 1
                41, 18467, 6334, 26500, 19169,
                Valor de semilla igual a 2
                45, 29216, 24198, 17795, 29484,
                Valor de semilla igual a 3
                48, 7196, 9294, 9091, 7031,
                Valor de semilla igual a 4
                51, 17945, 27159, 386, 17345,
              

Como podemos ver en esta última ejecucion, variando el valor de la semilla, obtenemos diferentes series de numeros aleatorios. Tambien podemos distinguir que la serie por defecto, y la serie con semila 1, son identicas. Sin embargo, si definimos una semilla de modo numérico, "hardcodeada", en cada ejecucion del programa, obtendremos exactamente la misma sucesión numérica. Por lo tanto, la siguiente solución sería utilizar una variable. Podriamos pedir al usuario por ejemplo, que ingrese una semilla. Incluso sin que el usuario lo sepa podríamos pedirle que ingrese su nombre, o su edad, y utilizar estos datos para generar una semilla, sin que el usuario lo sepa. De esta manera podríamos en cada ejecucion obtener aleatorios diferentes, pero aún con la posibilidad de que en dos ejecuciones diferentes del programa se dé la misma semilla. Por último podemos generar una semilla con variables que el usuario no pueda controlar. Esto podemos realizarlo por ejempo con un sensor de temperatura, o de humedad, con algun valor analógico como una entrada de microfono, etc. Pero existe una forma muy sencilla en C que nos permite tener una semilla de manera más aleatoria. Ésto se logra facilmente con una marca de tiempo.

Veremos en el siguiente código que utilizando una variable de tiempo, logramos una semilla que el usuario no puede controlar directamente.

              void main() {
                int i, j;
                time_t seed=time(NULL);
                printf("Semilla por default\n");
                for (i=0; i<5; i++){
                  printf("%d, ", rand());
                  }
                printf("\nSemilla de tiempo\n");
                srand(seed);
                for (i=0; i<5; i++){
                  printf("%d, ", rand());
                  }

                }
              
              Semilla por default
              41, 18467, 6334, 26500, 19169,
              Semilla de tiempo
              26312, 14257, 10669, 30850, 25818,
              

Esperando unos momentos, volvemos a ejecutar el codigo y obtenemos el siguiente mensaje

              Semilla por default
              41, 18467, 6334, 26500, 19169,
              Semilla de tiempo
              27833, 9510, 12301, 4930, 15514,
              

Si bien la semilla no es perfecta, para aplicaciones sencillas que no esten directamente relacionadas a la seguridad del sistema, incorporar una variable de tiempo a la generación de números random podría ser una excelente herramienta para obtener secuencias numéricas diferentes en cada ejecucución del programa.

Resumen

Sobre las limitaciones de la funcion rand() en C, y cómo generar numeros aleatorios diferentes en cada ejecucion del programa con ayuda de una marca de tiempo.