•»Huevos de yoshi (Ocio) •»Microsoft Developers •»Sin pelos en la Lengua ►Geek

Generando números aleatorios en C y C++

Por que nunca esta por demás…

Primero que nada déjenme decirles que el lenguaje C incorpora dos funciones [rand() y srand()] las cuales son pseudo generadoras de números aleatorios; que quiero decir con “pseudo” , pues que en realidad no generan números aleatorios, si no que siguen un algoritmo, que muestran el resultado de un conjunto de operaciones (“numero aleatorio”) ; que al final de cuentas puede ser predecido teniendo dicho algoritmo.

Función rand()

Hablemos de la función rand() esta genera un numero aleatorio en el rango de 0 y 32767 (solo enteros) ; para obtener estos números el algoritmo de la función rand() parte de un “numero semilla” , quiero decir un numero inicial al cual somete a un conjunto de operaciones para así generar los números “aleatorios”, lo único malo de esta función es que siempre que queramos generar números aleatorios este algoritmo siempre partera de la misma semilla y realizara las mismas operaciones, por lo que obtendremos los mismos números aleatorios una y otra vez… sin importar las veces que ejecutemos el programa.

A continuación un ejemplo:

   1: #include <iostream.h>

   2: #include <stdlib.h>

   3: //Dentro de stdlib.h encontramos la funcion rand()

   4: #include <conio.h>

   5:  

   6: int main(){

   7:  

   8: long int aleatorio=0;

   9:  

  10: cout<<"Programa que genera numeros aleatorios con la funcion
rand()"
<<endl;

  11: aleatorio = rand();

  12: cout<<"El numero aleatorio generado es: "<<aleatorio <<endl;

  13: cout<<"El numero generado se encuentra en un rango del 0 al "<< RAND_MAX <<endl;

  14: getch();

  15:  

  16: }

La función rand() se encuentra en la librería stdlib.h, la palabra reservada RAND_MAX -> regresa el valor máximo de la función rand().

Hasta aquí creo que todo simple… empezamos con la emoción al momento que queremos un numero aleatorio entre un rango personalizado, por ejemplo del 0 al 5:

   1: #include <iostream.h>

   2: #include <stdlib.h>

   3: #include <conio.h>

   4:  

   5: int main(){

   6: long int aleatorio=0;

   7:  

   8: cout<<"Programa que genera numeros aleatorios de rango 0 a 5"<<endl;

   9:  

  10: aleatorio = rand() % 6;

  11: cout<<"El numero aleatorio generado es: "<<aleatorio <<endl;

  12: getch();

  13: }

Estamos utilizando el operador modulo (%) que es el residuo de una división, para delimitar el rango de la variable “aleatorio”.

Analizando este paso, suponemos que el numero obtenido de la función rand() es el 12 y lo dividimos entre el numero 6;  obteniendo su modulo (residuo) que es igual a 0 (imagen1).

imageimagen1

La variable “aleatorio” que es igual a “0”  se encuentra en el rango de 0 a 5 y podemos confirmar que todas las variables “aleatorioque sean obtenidas aplicado a la función rand() una operación “modulo de 6 [ rand() % 6 ] se encontraran en este rango (0 a 5).

Para confirmar este argumento; asignemos otro valor ficticio a nuestra función rand(), por ejemplo el numero 8:

imagen2 

El numero obtenido es el 2, por lo que una vez mas nuestra variable “aleatorio” se encuentra en el rango de 0 a 5. Así podemos continuar asignando valores ficticios y arbitrarios a la función rand() y demostraremos que la variable “aleatorio” puede obtener el valor 0 ó 1 ó 2 ó 3 ó 4 ó 5  sea cual sea el dividendo con el que alimentemos la división.

El residuo de 12 entre 6 es cero “0” , lo comprobamos con el siguiente programa:

   1: #include <iostream.h>

   2: #include <stdlib.h>

   3: #include <conio.h>

   4:  

   5: int main(){

   6: int residuo=0;

   7: /*

   8: inicializar la variable var_rand en 12 es como

   9: simular que el resultado de la funcion

  10: rand fue igual a 12

  11: */

  12: int var_rand=12;

  13: //Digamos que equivale a

  14: //aleatorio= rand() % 6

  15: residuo= var_rand % 6;

  16: cout<<"El numero aleatorio generado es: "<<residuo <<endl;

  17: getch();

  18: }

La variable var_rand viene a emular el resultado de la función rand() solo que aquí nosotros damos el valor arbitrariamente (en este caso el 12).

🙂 muy bien , con eso espero allá quedado claro; ahora si quisiera un numero aleatorio entre el 0 y el 20 , solo cambiaria la línea del programa:

aleatorio = rand() % 21;

y si lo quiero en  un rango 0 a 50 entonces:

aleatorio = rand() % 51;

… y de rango 0 a 87:

aleatorio = rand() % 88;

Como ya nos dimos cuenta la formula es sencilla [ aleatorio = rand() % (N+1); ], si queremos hacer un rango de 0 a n , entonces la línea de código quedaría así:

aleatorio = rand() % n+1;

 
Pero aun con el rango continuamos con el problema que cada vez que ejecutamos el programa se generan los mismos números.

Función srand()

Para solucionar ese problema contamos con la función srand() con la cual indicamos el numero semilla con el que empezara el algoritmo para generar números aleatorios.

#include <iostream.h>

#include <stdlib.h>

#include <time.h>

#include <conio.h>

 

int main()

{

 long int aleatorio=0;

 srand(1);

 aleatorio = rand()%11;

 cout<<"Numero aleatorio de 0 a 10"<<endl;

 cout<<aleatorio;

getch();

}

Ya podemos generar realmente números aleatorios el único problema es que tenemos que cambiar el numero semilla manualmente (ósea borramos en el código el numero 1 de la función srand(1) y escribimos otro srand(34) )  efectivamente salen números aleatorios … pero si queremos GENERAR VARIOS NUMEROS ALEATORIOS EN UNA MISMA EJECUCION DEL PROGRAMA:

   1: #include <iostream.h>

   2: #include <stdlib.h>

   3: #include <time.h>

   4: #include <conio.h>

   5:  

   6: int main()

   7: {

   8:  long int aleatorio=0;

   9:  cout<<"Programa que genera 10 numeros aleatorios con srand(1)"<<endl;

  10:  srand(1);//Utilizo el numero 1 como semilla

  11:  for(int i=1; i<=10; i++){ // Ciclo for para generar 10 numeros

  12:  aleatorio = rand()%11;

  13:  cout<<i<<".-Aleatorio = "<<aleatorio<<endl;

  14:  }

  15: getch();

  16: }

🙂 Wow!! funciona… …. aunque tiene un detallito… si lo ejecutamos de nuevo SALDRAN LOS MISMOS NUMEROS y no queremos eso… lo que queremos es que cada vez que se ejecute el programa genere números aleatorios nuevos. Para solucionarlo utilizaremos un truquito el cual es inicializar nuestra semilla con la hora del sistema rand(hora_del_sistema) 😀 .

1.- Agregamos la librería time.h

2.- Modifico la línea srand(1) a srand (time(NULL))

   1: #include <iostream.h>

   2: #include <stdlib.h>

   3: #include <time.h>

   4: #include <conio.h>

   5:  

   6: int main()

   7: {

   8:  long int aleatorio=0;

   9:  cout<<"Programa que genera 10 numeros aleatorios con srand
(time(NULL))"
<<endl;

  10:  srand (time(NULL)); //Utilizo la hr del sistema como semilla

  11:  for(int i=1; i<=10; i++){ // Ciclo for para generar 10 numeros

  12:  aleatorio = rand()%11;

  13:  cout<<i<<".-Aleatorio = "<<aleatorio<<endl;

  14:  }

  15: getch();

  16: }

*DATO: la función srand() solamente la podemos usar una vez en el programa no traten de engañar al programa usándola varias veces por que los tirara de a locos

bueno.. esta es una forma BASICA de generar números aleatorios, existen otras cuantas como por ejemplo usar la función  getpid(); (regresa el ID del programa en ejecución asignado por el Sistema Operativo)  envés de usar time(NULL); y otras miles de formas mas.

Si desean pueden descargar el código de estos ejemplos:

page_white_compressed1[1] Descargar ejemplos de números aleatorios en C y C++

-Los ejemplos fueron compilados con Borland C++ 5.2

 

El dato extra:

Existen otras dos funciones para generar numero aleatorios las cuales son: drand48() y srand48() si desean saber mas de ellas visiten este link

Puedo recomendar un libro que se llama: El arte de la intrusión de autor Kevin Mitnick y editorial ALFAOMEGA.RA-MA donde en su primer capitulo se aprecia la importancia de generar números aleatorios que realmente sean aleatorios 😀 que mejor ejemplo que un CASINO ELECTRONICO ¿no?.

Update:

He mejorado la explicación del por que utilizamos el modulo para delimitar a un rango la generación de números aleatorios.

Si desean hacer un programa que genere números aleatorios con un rango definido ( numero mínimo a obtener y numero máximo a obtener) pueden revisar el siguiente programa: page_white_compressed1[1] DESCARGAR

[+][+][+]

Fuentes:

http://www.chuidiang.com/clinux/funciones/rand.php

http://www.agner.org/random/

http://www.daniweb.com/forums/thread1769.html

Complemento para Windows Live Writer

20 comentarios

  1. Interesante el tema como siempre, aunque también, como siempre, no podían faltar los «detalles» en la ortografía… Muy a pesar de que literalmente hace años no programo nada en C y que no logré entender la construcción de tus programas, no pude entender tu explicación de la lógica de porqué el rand() utiliza la función n+1 para obtener un número aleatorio entre 0 y un número n. Tampoco definiste si solo aplicaba para números enteros o también podían utilizarse números decimales… Compadre, ¡te estoy molestando! jejejeje No pero ya en serio, sería interesante saber más al respecto de esto. Muy buen contenido, ¡saludos!

    1. Tal como lo comenta @chuidiang

      «se usa %n+1 porque % es el resto de la división entre n+1. Si divides entre 51, el resto puede ir de 0 a 50.»

      Aunque concuerdo, contigo creo que are un Update al post para que quede más claro el por qué la fórmula para generar rangos es: rand() % N+1

      No hay más que agregar 😉
      ->
      Respecto a los detalles de la ortografía , esto es pa’ que vean que si lo escribo yo y no me lo fusilo :). No ya enserio procurare revisarlo aun cuando el «Live Writer» me corrige.
      ->
      Las funciones para generar números aleatorios decimales son las drand48() y srand48() que menciono como datos extra

  2. @Roman, se usa %n+1 porque % es el resto de la división entre n+1. Si divides entre 51, el resto puede ir de 0 a 50. Por eso, si quieres números entre 0 y 50, debes dividir entre 51.

    Se bueno.

  3. Gracias a Chuidiang y al buen Darkchicles por su aclaración de la lógica del rango finito de números arbitrarios que (siendo sincero), aunque tampoco entendí al principio con la explicación de Chuidiang, la explicación de Darkchicles en la actualización de éste post me ayudó finalmente a entender del todo la razón del n+1 (o al menos eso creo…).

    Entonces, si es verdad que entendí bien, lo que se intenta decir en un tono más «fresa» aquí, es que se utiliza la función rand()%n+1 para definir un rango de números aleatoreos de 0 a n porque, sin importar el número que se divida entre n+1, ya sea menor o mayor a éste, el residuo resultado de tal división siempre será menor o igual al número n y nunca mayor a éste. Siendo ésto cierto, si n+1=16, el residuo de la división de cualquier número entre 16 será menor o igual a 15, pero nunca mayor, entonces, definiendo como ejemplo a rand()=27, el residuo de la división de rand()/n+1=27/16 será 11=27%16=rand()%n+1, lo cual cumple perfectamente con la condición ya mencionada, 11<15… ¿Me viajé mucho? Por favor, ¡corríjanme si me equivoco!

    Por cierto, gracias también por el dato de los operadores aleatorios para números decimales… Compadre, ¡está bien interesante pero no tengo idea de cómo aplicarlo! Saludos.

    1. Asi es, tienes razon osease estas en lo correcto hablando en codigo seria algo similar a:

      aleatorio = rand() % 16

      donde rand() tiene un valor arbitrario definido por ti de: 27 ; efectivamente su residuo es 11 , que se encuentra dentro del rango 0 – 15 o como dices tu 11<15 .

      Una de sus aplicaciones mas comunes son los juegos de cartas , juegos de dados y programas de estadistica, pero para todos estos es mejor usar algoritmos diseñados por nosotros mismos que generen numeros aleatorios de una forma mas compleja 😀

      Un saludo!

  4. Holap:

    Como un dato curioso, la funcion «time( )» con el argumento NULL (o sea, «time(NULL)») devuelve la cantidad de segundos que han pasado desde el 01 de enero de 1970… por eso es que es ideal para usarla como «semilla» de la función «rand()», pues cada segundo devolverá un número diferente… xD

    Saludooos 😛

  5. ME interesa mucho este mundo de la programación queria un poco de ayudo con respecto a generar varios numeros con respecto a una entrada (semilla), si alguien pudiera ayudarme estaria agradeciso, sigan asi !!

  6. un pregunta…. y si kiero dentro de un rango que no necesariamente sea de de 0 a n sino de un m a n ojala me ayuden esque nose muxo de c++ y tengo tarea e.e

  7. me olvidaba decirle que ese rango io tengo que ingresarlo por teclado y como entons pondria la formula io lo eh pensado algo asi x=rand()%(b+1-a)+a; aw nuse ayuden please

  8. a mi me dice Error 1 fatal error C1083: No se puede abrir el archivo incluir: ‘iostream.h’: No such file or directory que hago ayudaaaaaa!!

  9. Tengo una pregunta, si tengo un programa que me genera un conjunto de numeros aleatorios y ese programa lo ejecutó 50 veces (con un script de shell), ¿cómo puedo hacerle para que no me genere los mismos números? ya que aunque tiene el srand(time), se generan en el mismo segundo.

Deja un comentario