¿Cómo se relaciona srand con la función rand?

5 minutos de lectura

avatar de usuario
Flecha

Entiendo que la función rand() genera los mismos números cada vez que la ejecuta si no cambia el número inicial. Ahí es donde entra en juego srand(). El tiempo siempre cambia, así que sé que debes pasar el parámetro time(null) a srand. Mi pregunta es con el siguiente código de un sitio de tutoriales.

int main()
{
    int i, n=5;
    time_t t;

    /* Intializes random number generator */
    srand((unsigned) time(&t));

    /* Print 5 random numbers from 0 to 50 */
    for( i = 0 ; i < n ; i++ ) {
        printf("%d\n", rand() % 50);
    }

    return(0);
}

no veo ningun enlace del srand

((unsigned) time(&t)); 

y rand.

printf("%d\n", rand() % 50);

¿Dónde está la conexión entre rand y srand? Lo que quiero decir o espero es que asumo que rand() obtendrá algún parámetro de srand() para que sepa generar números diferentes cada vez. Supongo que se vería algo así como rand(srand(time(null));

Es como inicializar una variable sin usarla para mí. srand se está inicializando, pero no veo que se esté usando.

¿Rand genera números diferentes porque srand se llama primero antes que rand?

  • En la línea de comando, puede ver la documentación de estas funciones escribiendo man 3 rand y man 3 srand.

    – tlehman

    22 de enero de 2014 a las 3:27

La semilla del número aleatorio es una variable estática global. rand y srand ambos tienen acceso a ella.

avatar de usuario
paxdiablo

srand() establece la semilla que es utilizada por rand para generar números “aleatorios” (entre comillas porque generalmente son pseudoaleatorios). si no llamas srand antes de su primera llamada a randes como si hubieras llamado srand(1) para establecer la semilla en uno.

Una gran cantidad de código usa la hora actual como la semilla para hacer que cada programa se ejecute usando una secuencia diferente de números aleatorios, pero siempre puede cambiar eso a algo como srand(42) durante la depuración, con fines de repetibilidad. Y la llamada a time() en realidad no necesitar una variable para colocar el tiempo, simplemente puede pasar NULL:

srand (time (NULL));

Todo podría implementarse en un solo archivo con algo como lo siguiente, el ejemplo dado en el estándar (ISO C99 7.20.2.2 The srand function).

// RAND_MAX assumed to be 32767.
static unsigned long int next = 1;
void srand(unsigned int seed) { next = seed; }
int rand(void) {
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

El hecho de que next es una variable estática en la parte superior del archivo significa que es invisible para todo lo que está fuera del archivo pero visible para todo lo que está dentro (una especie de global localizado). Ese es el método de comunicación entre srand() y rand().

  • Creo que lo que pide OP es más como la implementación de estas dos funciones.

    – WiSaGaN

    22 de enero de 2014 a las 3:29


  • Una pregunta aquí: ¿Cómo ha llegado el estándar a los grandes números dentro del rand() ¿función? ¿Cuál es la lógica detrás de esto?

    – Gopi

    09/04/2015 a las 13:52

No ves un enlace porque (¡afortunadamente!) quien haya diseñado rand() decidió mantener eso como un detalle de implementación, de la misma manera que no ve lo que hay dentro de un FILE de stdio; la desventaja es que decidieron convertir ese estado en una variable global (pero oculta) en lugar de un parámetro para el generador.

Contraste eso con lo obsoleto rand_r(): el estado es un entero sin signo (se supone que es >= 32 bits), lo que significa que incluso es prohibido usar cualquier generador mejor cuyo estado sea mayor que ese, ¡simplemente porque no hay espacio para almacenarlo!

Al mantener oculto el estado interno, en cambio, uno es libre de elegir cualquier algoritmo que funcione mejor (velocidad, período, …) y usarlo detrás de escena, siempre que garantice que llamar a rand sin inicializar es lo mismo que llamar a srand con semilla==1.

Paxdiablo te mostró el ejemplo del estándar C; ver por ejemplo http://en.wikipedia.org/wiki/Multiplicar-con-llevar para un ejemplo usando un generador diferente que podría ocultar detrás de rand/srand.

Solo para ser extra-extra claro: tenía rand_r sido diseñado apropiadamente, habría un tipo opaco, digamos rand_t (que podría ser un número entero, una estructura, una matriz, …), que le pasaría a rand_r y a algunos hipotéticos srand_rcomo en

rand_t state;
srand_r(&state, 1);
n = rand_r(&state);

La función rand es exactamente así, excepto que solo hay una state variable.

  • Estoy de acuerdo contigo en todos los puntos. Pero creo que OP solo quería saber cómo rand sabe lo que es la semilla si srand no devuelve algo a lo que pasas rand como parámetro. Incluso si no sabemos (¡no deberíamos!) cuántos bits de estado hay o el algoritmo exacto que genera los números aleatorios, el hecho de que el estado es necesario, su vida útil supera la de una llamada de función y es accesible para dos funciones es una consecuencia ineludible de ser un generador de números aleatorios con semillas: no hay abstracción que no necesite una variable estática en alguna parte.

    – sqykly

    25 de enero de 2014 a las 10:11

rand te da una secuencia pseudoaleatoria de números.

Este número es generado por un algoritmo que devuelve una secuencia de números aparentemente no relacionados cada vez que se llama. Este algoritmo usa una semilla para generar la serie, que debe inicializarse con algún valor distintivo usando la función srand.

srand en cada llamada establece el puntero en alguna ubicación en la lista en la que está ingresando. Si no lo llama en cada intento o le da una semilla fija, le dará la misma secuencia. Muchos sugieren dar el segundo actual como semilla. Pero si intenta ejecutar su código en el mismo segundo dos veces, obtendrá la misma secuencia.

Por cada valor inicial diferente utilizado en una llamada a srand, se puede esperar que el generador de números pseudoaleatorios genere una sucesión diferente de resultados en las llamadas subsiguientes a rand para mayor explicación

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad