Nota : No lo use rand()para seguridad. Si necesita un número criptográficamente seguro, consulte esta respuesta .
#include<time.h>#include<stdlib.h>
srand(time(NULL));// Initialization, should only be called once.int r = rand();// Returns a pseudo-random integer between 0 and RAND_MAX.
+1 por simplicidad, pero probablemente sea una buena idea enfatizar que srand () solo debe llamarse una vez . Además, en una aplicación con subprocesos, es posible que desee asegurarse de que el estado del generador se almacena por subproceso y sembrar el generador una vez para cada subproceso.
RBerteig 05 de
41
@trusktr, es complicado. Aquí hay una razón: time()solo cambia una vez por segundo. Si inicia desde time(), para cada llamada a rand(), obtendrá el mismo valor para cada llamada durante un solo segundo. Pero la razón más importante es que las propiedades rand()y funciones como esta se conocen mejor para el caso de uso donde se siembran exactamente una vez por ejecución, y no en cada llamada. Dependiendo de la "aleatoriedad" con propiedades no comprobadas o no probadas conduce a problemas.
RBerteig
99
@trusktr para un generador congruencial lineal simple (que es lo que rand()generalmente es) sembrar con rand(), en el mejor de los casos, no tendría ningún efecto, y en el peor de los casos rompería las cualidades conocidas del generador. Este es un tema profundo. Comience leyendo el Capítulo 3 de Knuth Vol. 2 sobre números aleatorios como la mejor introducción a las matemáticas y dificultades.
RBerteig
21
Evite una advertencia del compilador con un elenco:srand((unsigned int)time(NULL));
GiovaMaster
99
Tenga en cuenta que esta sigue siendo una forma débil de ver el PRNG. El año pasado, un virus de tipo cryptolocker en Linux cometió el error de sembrar con el tiempo, y esto redujo drásticamente el espacio de búsqueda. Todo lo que tenía que hacer era tener una idea decente de cuándo se produjo la infección y luego probar las semillas de esa época. Lo último que escuché es que la mejor fuente de aleatoriedad es / dev / urandom, que supuestamente proviene de una combinación de fuentes caóticas como las temperaturas en el hardware. Sin embargo, si todo lo que realmente desea es que su programa actúe de manera diferente en cada ejecución, la solución anterior está bien.
Jemenake
238
La rand()función en <stdlib.h>devuelve un entero pseudoaleatorio entre 0 y RAND_MAX. Puedes usar srand(unsigned int seed)para establecer una semilla.
Es una práctica común usar el %operador en conjunto con rand()para obtener un rango diferente (aunque tenga en cuenta que esto arroja algo de uniformidad). Por ejemplo:
/* random int between 0 and 19 */int r = rand()%20;
Si realmente te importa la uniformidad, puedes hacer algo como esto:
/* Returns an integer in the range [0, n).
*
* Uses rand(), and so is affected-by/affects the same seed.
*/int randint(int n){if((n -1)== RAND_MAX){return rand();}else{// Supporting larger values for n would requires an even more// elaborate implementation that combines multiple calls to rand()
assert (n <= RAND_MAX)// Chop off all of the values that would cause skew...int end = RAND_MAX / n;// truncate skew
assert (end >0);
end *= n;// ... and ignore results from rand() that fall above that limit.// (Worst case the loop condition should succeed 50% of the time,// so we can expect to bail out of this loop pretty quickly.)int r;while((r = rand())>= end);return r % n;}}
Es una práctica común , pero no es la correcta. Mira esto y esto .
Lazer
35
@Lazer: Por eso dije "aunque ten en cuenta que esto quita un poco la uniformidad".
Laurence Gonsalves
3
@AbhimanyuAryan The %es el operador de módulo. Le da el resto de una división entera, por x % nlo que siempre le dará un número entre 0y n - 1(siempre xy cuando nsean positivos). Si todavía lo encuentra confuso, intente escribir un programa que icuente de 0 a 100, e imprima i % npara algunos nde su elección más pequeños que 100.
Laurence Gonsalves
2
@necromancer Seguí adelante y agregué una solución perfectamente uniforme.
Laurence Gonsalves
2
@Lazer, el segundo enlace que publicaste en realidad aún no es perfectamente uniforme. Lanzar a un doble y viceversa no ayuda. El primer enlace que publicaste tiene una solución perfectamente uniforme, aunque se repetirá mucho para los límites superiores pequeños. Agregué una solución perfectamente uniforme a esta respuesta que no debería repetirse tanto incluso para los límites superiores pequeños.
Laurence Gonsalves
53
Si necesita caracteres aleatorios o enteros seguros:
En términos más generales, use/dev/urandom , no /dev/random. No OpenSSL (u otros PRNG de espacio de usuario).
Por ejemplo:
#include"sodium.h"int foo(){char myString[32];uint32_t myInt;if(sodium_init()<0){/* panic! the library couldn't be initialized, it is not safe to use */return1;}/* myString will be an array of 32 random bytes, not null-terminated */
randombytes_buf(myString,32);/* myInt will be a random number between 0 and 9 */
myInt = randombytes_uniform(10);}
randombytes_uniform() es criptográficamente seguro e imparcial.
¿Se debe sembrar libsodium RNG antes de llamar a randombytes_buf?
user2199593
Solo llame sodium_init()en algún momento. No te preocupes por el RNG, usa el núcleo.
Scott Arciszewski
Nota: Aprobé la edición reciente sodium_init()aunque no sea necesariamente parte de mi ejemplo porque es un detalle importante.
Scott Arciszewski
29
Vamos a pasar por esto. Primero usamos la función srand () para sembrar el aleatorizador. Básicamente, la computadora puede generar números aleatorios basados en el número que se alimenta a srand (). Si proporcionó el mismo valor inicial, se generarían los mismos números aleatorios cada vez.
Por lo tanto, tenemos que sembrar el aleatorizador con un valor que siempre esté cambiando. Hacemos esto al darle el valor del tiempo actual con la función time ().
Ahora, cuando llamamos a rand (), se producirá un nuevo número aleatorio cada vez.
#include<stdio.h>int random_number(int min_num,int max_num);int main(void){
printf("Min : 1 Max : 40 %d\n", random_number(1,40));
printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));return0;}int random_number(int min_num,int max_num){int result =0, low_num =0, hi_num =0;if(min_num < max_num){
low_num = min_num;
hi_num = max_num +1;// include max_num in output}else{
low_num = max_num +1;// include max_num in output
hi_num = min_num;}
srand(time(NULL));
result =(rand()%(hi_num - low_num))+ low_num;return result;}
Código agradable, pero no es una buena idea llamar 'srand (time (NULL));'. Este método produce el mismo número cuando se llama en un bucle for.
RayOldProf
1
Las ediciones sugeridas que involucran código a menudo se rechazan. Alguien hizo uno aquí con el comentario "el algoritmo estaba equivocado. Podría producir números mayores que el máximo". No he evaluado el reclamo yo mismo.
Martin Smith
1
@Martin Smith Problemas: 1) debe ser else{ low_num=max_num; hi_num=min_num+1;2) falla cuando hi_num - low_num > INT_MAX. 3) Omite valores en la situación rara INT_MAX > hi_num - low_num > RAND_MAX.
chux - Restablece a Monica
1
Volver a colocarlo así hará que esta función produzca el mismo número si se llama varias veces en el mismo segundo. Si realmente desea volver a sembrarlo, vuelva a hacerlo solo una vez por segundo.
Élektra
1
Menor: hi_num = max_num + 1;carece de protección contra el desbordamiento.
chux - Restablece a Mónica el
25
Si necesita números pseudoaleatorios de mejor calidad que los que stdlibofrece, consulte Mersenne Twister . También es más rápido. Las implementaciones de muestra son abundantes, por ejemplo aquí .
+1: Parece genial pero solo estaba haciendo un juego de adivinanzas. Si fuera a usar un generador de números aleatorios en una aplicación comercial, definitivamente lo usaría.
Kredns 01 de
44
No use un Mersenne Twister, use algo bueno como xoroshiro128 + o PCG. (Enlace relevante.)
Veedrac
17
La función estándar de C es rand(). Es lo suficientemente bueno como para repartir cartas por solitario, pero es horrible. Muchas implementaciones de rand()ciclo a través de una lista corta de números, y los bits bajos tienen ciclos más cortos. La forma en que algunos programas llaman rand()es horrible, y calcular una buena semilla para pasar srand()es difícil.
La mejor manera de generar números aleatorios en C es usar una biblioteca de terceros como OpenSSL. Por ejemplo,
#include<stdint.h>#include<stdio.h>#include<stdlib.h>#include<openssl/rand.h>/* Random integer in [0, limit) */unsignedint random_uint(unsignedint limit){union{unsignedint i;unsignedchar c[sizeof(unsignedint)];} u;do{if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}}while(u.i <(-limit % limit));/* u.i < (2**size % limit) */return u.i % limit;}/* Random double in [0.0, 1.0) */double random_double(){union{uint64_t i;unsignedchar c[sizeof(uint64_t)];} u;if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}/* 53 bits / 2**53 */return(u.i >>11)*(1.0/9007199254740992.0);}int main(){
printf("Dice: %d\n",(int)(random_uint(6)+1));
printf("Double: %f\n", random_double());return0;}
¿Por qué tanto código? Otros lenguajes como Java y Ruby tienen funciones para enteros aleatorios o flotantes. OpenSSL solo da bytes aleatorios, así que trato de imitar cómo Java o Ruby los transformaría en enteros o flotantes.
Para los enteros, queremos evitar el sesgo de módulo . Supongamos que tenemos algunos enteros aleatorios de 4 dígitos rand() % 10000, pero rand()solo podemos devolver 0 a 32767 (como lo hace en Microsoft Windows). Cada número del 0 al 2767 aparecería con mayor frecuencia que cada número del 2768 al 9999. Para eliminar el sesgo, podemos volver a intentar rand()mientras el valor esté por debajo de 2768, porque los valores de 30000 de 2768 a 32767 corresponden de manera uniforme a los valores de 10000 de 0 a 9999.
Para flotantes, queremos 53 bits aleatorios, porque un doublecontiene 53 bits de precisión (suponiendo que sea un doble IEEE). Si usamos más de 53 bits, obtenemos sesgo de redondeo. Algunos programadores escriben código como rand() / (double)RAND_MAX, pero rand()pueden devolver solo 31 bits, o solo 15 bits en Windows.
OpenSSL se inicia RAND_bytes(), tal vez leyendo /dev/urandomen Linux. Si necesitamos muchos números aleatorios, sería demasiado lento leerlos todos /dev/urandom, ya que deben copiarse del núcleo. Es más rápido permitir que OpenSSL genere más números aleatorios a partir de una semilla.
Más sobre números aleatorios:
Perl's Perl_seed () es un ejemplo de cómo calcular una semilla en C para srand(). Mezcla bits de la hora actual, la ID del proceso y algunos punteros, si no puede leer /dev/urandom.
Gracias por esta respuesta extendida. Tenga en cuenta que de las 24 respuestas actuales a esta pregunta, usted fue el único con una interpretación adicional para tratar float/ double, por lo que he aclarado la pregunta para mantener los intnúmeros para evitar que sea demasiado amplia. Hay otras preguntas que tratan específicamente de C float/ doublevalores aleatorios, por lo que puede volver a publicar su segunda mitad de su respuesta a preguntas tales como stackoverflow.com/questions/13408990/...
Coeur
11
Si su sistema admite la arc4randomfamilia de funciones, recomendaría usarlas en lugar de la randfunción estándar .
arc4random devuelve un entero aleatorio sin signo de 32 bits.
arc4random_bufpone contenido aleatorio en su parámetro buf : void *. La cantidad de contenido está determinada por el bytes : size_tparámetro.
arc4random_uniformdevuelve un entero aleatorio sin signo de 32 bits que sigue la regla:, 0 <= arc4random_uniform(limit) < limitdonde limit también es un entero sin signo de 32 bits.
arc4random_stirlee datos /dev/urandomy los transfiere para arc4random_addrandomaleatorizar adicionalmente su grupo interno de números aleatorios.
arc4random_addrandomes utilizado por arc4random_stirpara llenar su grupo interno de números aleatorios de acuerdo con los datos que se le pasan.
Si no tiene estas funciones, pero está en Unix, puede usar este código:
/* This is C, not C++ */#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<errno.h>#include<unistd.h>#include<stdlib.h>/* exit */#include<stdio.h>/* printf */int urandom_fd =-2;void urandom_init(){
urandom_fd = open("/dev/urandom", O_RDONLY);if(urandom_fd ==-1){int errsv = urandom_fd;
printf("Error opening [/dev/urandom]: %i\n", errsv);
exit(1);}}unsignedlong urandom(){unsignedlong buf_impl;unsignedlong*buf =&buf_impl;if(urandom_fd ==-2){
urandom_init();}/* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
read(urandom_fd, buf,sizeof(long));return buf_impl;}
La urandom_initfunción abre el /dev/urandomdispositivo y coloca el descriptor de archivo urandom_fd.
La urandomfunción es básicamente la misma que una llamada a rand, excepto que es más segura y devuelve un long(fácilmente modificable).
Sin embargo, /dev/urandompuede ser un poco lento, por lo que se recomienda que lo use como semilla para un generador de números aleatorios diferente.
Si el sistema no tiene una /dev/urandom, pero no tienen un /dev/randomarchivo o similar, entonces sólo tiene que cambiar la ruta pasó a openen urandom_init. Las llamadas y las API utilizadas en urandom_inity urandomson (creo) compatibles con POSIX, y como tal, deberían funcionar en la mayoría, si no en todos los sistemas compatibles con POSIX.
Notas: Una lectura de /dev/urandomNO se bloqueará si no hay suficiente entropía disponible, por lo que los valores generados en tales circunstancias pueden ser criptográficamente inseguros. Si está preocupado por eso, use /dev/random, que siempre se bloqueará si no hay suficiente entropía.
Si está en otro sistema (es decir, Windows), utilice rando alguna API interna no portátil dependiente de la plataforma específica de Windows.
Envoltorio para la función urandom, rando arc4randomlas llamadas:
STL no existe para C. Usted tiene que llamar rand, o mejor aún, random. Estos se declaran en el encabezado de la biblioteca estándar stdlib.h. randes POSIX, randomes una función de especificación BSD.
La diferencia entre randy randomes que randomdevuelve un número aleatorio de 32 bits mucho más utilizable, y randgeneralmente devuelve un número de 16 bits. Las páginas de manual de BSD muestran que los bits más bajos randson cíclicos y predecibles, por lo que randes potencialmente inútil para números pequeños.
@Neil: dado que todas las respuestas hasta ahora mencionan el STL, sospecho que la pregunta se editó rápidamente para eliminar una referencia innecesaria.
Michael Burr
rand () no es inútil para números pequeños: puede desplazarlos y usar solo los bits altos más aleatorios si realmente lo necesita.
Chris Lutz
@Chris, puede hacerlo si se conoce el tamaño del número aleatorio, pero si el tamaño requerido del número aleatorio cambia durante el tiempo de ejecución (como barajar una matriz dinámica, etc.) sería difícil evitar tal advertencia.
dreamlax
No puedo encontrar ninguna función aleatoria aquí :-(
kasia.b
@ kasia.b en ese enlace, hay extern int rand(void);y extern void srand(unsigned int);.
RastaJedi
7
Eche un vistazo a ISAAC (Indirección, Cambio, Acumular, Agregar y Contar). Está distribuido uniformemente y tiene una duración promedio del ciclo de 2 ^ 8295.
Que desea utilizar rand(). Nota ( MUY IMPORTANTE ): asegúrese de establecer la semilla para la función rand. Si no lo hace, sus números aleatorios no son realmente aleatorios . Esto es muy, muy, muy importante. Afortunadamente, generalmente puede usar alguna combinación del temporizador de tic del sistema y la fecha para obtener una buena semilla.
Dos puntos a) sus números aleatorios no son "verdaderamente" aleatorios, sin importar cómo se siembra el generador. Y b) es muy conveniente que la secuencia pseudoaleatoria sea siempre la misma en muchas circunstancias, por ejemplo, para pruebas.
16
Si es MUY IMPORTANTE que su número sea verdaderamente aleatorio, no debería usar la función rand ().
tylerl
1
Los valores de rand no son "verdaderamente" aleatorios, sin importar si establece la semilla o no. Dada una semilla conocida, la secuencia es predecible. La generación de números aleatorios "verdaderamente" es difícil. No hay entropía involucrada con rand.
dreamlax
2
Por supuesto que lo harán: la biblioteca sembrará el generador para usted (probablemente a cero, pero esa es una semilla válida).
44
Ah, pero el algoritmo conocido / semilla conocida es esencial para depurar cualquier programa que use números aleatorios. No es inusual registrar la semilla utilizada junto con una ejecución de simulación para que pueda recrearse para un análisis más detallado. No llamar a srand () es equivalente a llamar a srand (1).
RBerteig 05 de
4
FWIW, la respuesta es que sí, hay una stdlib.hfunción llamada rand; Esta función se ajusta principalmente para la velocidad y la distribución, no para la imprevisibilidad. Casi todas las funciones aleatorias incorporadas para varios lenguajes y marcos usan esta función de manera predeterminada. También hay generadores de números aleatorios "criptográficos" que son mucho menos predecibles, pero funcionan mucho más lentamente. Deben usarse en cualquier tipo de aplicación relacionada con la seguridad.
agregar srand (rand ()) no aumenta la aleatoriedad de la secuencia si este programa se ejecuta varias veces en 1 segundo. time (NULL) aún devolverá el mismo valor para cada uno de ellos, el primer rand () devolverá el mismo largo y la segunda llamada a srand () tendrá el mismo valor, lo que dará como resultado que todavía tenga la misma secuencia aleatoria. El uso de la dirección de argc podría ayudar, solo si se garantiza que esta dirección será diferente en cada ejecución del programa, lo que no siempre es cierto.
theferrit32
3
Bueno, STL es C ++, no C, así que no sé lo que quieres. Sin embargo, si desea C, existen las funciones rand()y srand():
int rand(void);void srand(unsigned seed);
Ambos son parte de ANSI C. También existe la random()función:
long random(void);
Pero, por lo que puedo decir, random()no es ANSI C. estándar. Una biblioteca de terceros puede no ser una mala idea, pero todo depende de qué tan aleatorio de un número realmente necesite generar.
También puede obtener un número aleatorio de cualquier servicio en línea como random.org Bounty si incluye una forma portátil y eficiente de hacer esto en C.
MD XF
2
#include<stdio.h>#include<stdlib.h>void main(){int visited[100];int randValue, a, b, vindex =0;
randValue =(rand()%100)+1;while(vindex <100){for(b =0; b < vindex; b++){if(visited[b]== randValue){
randValue =(rand()%100)+1;
b =0;}}
visited[vindex++]= randValue;}for(a =0; a <100; a++)
printf("%d ", visited[a]);}
luego defina en la parte superior con variables @ b4hand
Muhammad Sadiq
En el momento en que hice ese comentario, no tenía permisos de edición universales y, en general, los cambios de código que cambiaban la respuesta real serían rechazados. Si no te importa arreglar tu respuesta, puedo hacerlo.
b4hand
Si su intención era producir una permutación aleatoria de valores únicos, este código todavía tiene un error. Produce el valor 84 dos veces y no produce el valor 48. Además, no genera el generador de números aleatorios, por lo que la secuencia es la misma en cada ejecución.
b4hand
1
las variables ayb están definidas en este código. Está libre de errores. No hay sintaxis ni error lógico.
Muhammad Sadiq
Incorrecto. Ya he confirmado a mano la salida como mencioné.
b4hand
1
#include<stdio.h>#include<dos.h>int random(int range);int main(void){
printf("%d", random(10));return0;}int random(int range){struct time t;int r;
gettime(&t);
r = t.ti_sec % range;return r;}
En las CPU modernas x86_64, puede usar el generador de números aleatorios de hardware a través de _rdrand64_step()
Código de ejemplo:
#include<immintrin.h>uint64_t randVal;if(!_rdrand64_step(&randVal)){// Report an error here: random number generation has failed!}// If no error occured, randVal contains a random 64-bit number
#include<stdio.h>#include<stdlib.h>#include<time.h>//generate number in range [min,max)int random(int min,int max){int number = min + rand()%(max - min);return number;}//Driver codeint main(){
srand(time(NULL));for(int i =1; i <=10; i++){
printf("%d\t", random(10,100));}return0;}
Al escuchar una buena explicación de por qué usar rand()para producir números aleatorios distribuidos uniformemente en un rango dado es una mala idea, decidí echar un vistazo a lo sesgada que está la salida en realidad. Mi caso de prueba fue el lanzamiento justo de dados. Aquí está el código C:
#include<stdio.h>#include<stdlib.h>#include<time.h>int main(int argc,char*argv[]){int i;int dice[6];for(i =0; i <6; i++)
dice[i]=0;
srand(time(NULL));constint TOTAL =10000000;for(i =0; i < TOTAL; i++)
dice[(rand()%6)]+=1;double pers =0.0, tpers =0.0;for(i =0; i <6; i++){
pers =(dice[i]*100.0)/ TOTAL;
printf("\t%1d %5.2f%%\n", dice[i], pers);
tpers += pers;}
printf("\ttotal: %6.2f%%\n", tpers);}
No sé qué tan uniforme necesita que sean sus números aleatorios, pero lo anterior parece lo suficientemente uniforme para la mayoría de las necesidades.
Editar: sería una buena idea inicializar el PRNG con algo mejor que time(NULL).
rand () puede fallar en otras pruebas de aleatoriedad, como las pruebas intransigentes . rand () difiere de una plataforma a otra; Los valores rand () de GNU / Linux pueden ser mejores que los valores de BSD o Windows.
George Koehler
Esta no es una forma válida de probar la aleatoriedad.
Veedrac
Depende del propósito y del modelo de amenaza / riesgo. Para RNG criptográficamente fuerte, seguro, use RDRAND (o RDSEED). Para un simple lanzador de dados (no a nivel de casino) en mi humilde opinión, lo anterior debería ser suficiente. La palabra clave es " suficientemente buena ".
Ratón el
0
Tuve un problema grave con el generador de números pseudoaleatorios en mi aplicación reciente: repetidamente llamé a mi programa C a través de un script pyhton y estaba usando como semilla el siguiente código:
srand(time(NULL))
Sin embargo, desde:
rand generará la misma secuencia pseudoaleatoria y dará la misma semilla en srand (ver man srand);
Como ya se dijo, la función de tiempo cambia solo de segundo a segundo: si su aplicación se ejecuta varias veces dentro del mismo segundo, timedevolverá el mismo valor cada vez.
Mi programa generó la misma secuencia de números. Puede hacer 3 cosas para resolver este problema:
mezclar la salida del tiempo con alguna otra información que cambia en las ejecuciones (en mi aplicación, el nombre de la salida):
La opción 3 le garantiza (hasta donde yo sé) la mejor aleatoriedad inicial, pero puede crear una diferencia solo en aplicaciones muy rápidas. En mi opinión, la opción 2 es una apuesta segura.
Incluso con estas heurísticas, no confíe en rand () para obtener datos criptográficos.
domenukk
rand()No debería usarse para datos criptográficos, estoy de acuerdo. Al menos para mí, mi aplicación no incluía datos criptográficos, por lo que para mí estaba bien el método dado.
Koldar
0
A pesar de todas las sugerencias de personas rand()aquí, ¡no querrás usar a rand()menos que tengas que hacerlo! Los números aleatorios que rand()produce a menudo son muy malos. Para citar de la página de manual de Linux:
Las versiones de rand()y srand()en la Biblioteca Linux C usan el mismo generador de números aleatorios que random(3)y srandom(3), por lo que los bits de orden inferior deben ser tan aleatorios como los bits de orden superior. Sin embargo, en implementaciones antiguas de rand () y en implementaciones actuales en diferentes sistemas, los bits de orden inferior son mucho menos aleatorios que los bits de orden superior . No utilice esta función en aplicaciones destinadas a ser portátiles cuando se necesita una buena aleatoriedad. ( Use en su random(3)lugar )
En cuanto a la portabilidad, random()también está definida por el estándar POSIX desde hace bastante tiempo. rand()es anterior, ya apareció en la primera especificación POSIX.1 (IEEE Std 1003.1-1988), mientras que random()apareció por primera vez en POSIX.1-2001 (IEEE Std 1003.1-2001), pero el estándar POSIX actual ya es POSIX.1-2008 (IEEE Std 1003.1-2008), que recibió una actualización hace solo un año (IEEE Std 1003.1-2008, edición de 2016). Por lo tanto, consideraría random()que es muy portátil.
POSIX.1-2001 también introdujo las funciones lrand48()y mrand48(), ver aquí :
Esta familia de funciones generará números pseudoaleatorios utilizando un algoritmo lineal congruencial y una aritmética de enteros de 48 bits.
Y una fuente pseudoaleatoria bastante buena es la arc4random()función que está disponible en muchos sistemas. No forma parte de ningún estándar oficial, apareció en BSD alrededor de 1997, pero puede encontrarlo en sistemas como Linux y macOS / iOS.
@ BjörnLindqvist Windows tampoco es un sistema POSIX; Es prácticamente el único sistema en el mercado que no admite al menos las API POSIX básicas (que incluso admiten sistemas como iOS). Windows solo es compatible, rand()ya que también lo requiere el estándar C. Para cualquier otra cosa, necesita una solución especial solo para Windows, como de costumbre. #ifdef _WIN32es la frase que verá con mayor frecuencia en el código multiplataforma que desea admitir Windows y, por lo general, hay una solución que funciona con todos los sistemas y una que solo se requiere para Windows.
Mecki
0
Para aplicaciones Linux C:
Este es mi código modificado de una respuesta anterior que sigue mis prácticas de código C y devuelve un búfer aleatorio de cualquier tamaño (con los códigos de retorno adecuados, etc.). Asegúrese de llamar urandom_open()una vez al comienzo de su programa.
int gUrandomFd =-1;int urandom_open(void){if(gUrandomFd ==-1){
gUrandomFd = open("/dev/urandom", O_RDONLY);}if(gUrandomFd ==-1){
fprintf(stderr,"Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
errno, strerror(errno));return-1;}else{return0;}}void urandom_close(void){
close(gUrandomFd);
gUrandomFd =-1;}//// This link essentially validates the merits of /dev/urandom:// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers///int getRandomBuffer(uint8_t*buf,int size){int ret =0;// Return valueif(gUrandomFd ==-1){
fprintf(stderr,"Urandom (/dev/urandom) file not open\n");return-1;}
ret = read(gUrandomFd, buf, size);if(ret != size){
fprintf(stderr,"Only read [%d] bytes, expected [%d]\n",
ret, size);return-1;}else{return0;}}
Mi solución minimalista debería funcionar para números aleatorios en el rango [min, max). Úselo srand(time(NULL))antes de invocar la función.
int range_rand(int min_num,int max_num){if(min_num >= max_num){
fprintf(stderr,"min_num is greater or equal than max_num!\n");}return min_num +(rand()%(max_num - min_num));}
Intente esto, lo puse a partir de algunos de los conceptos ya mencionados anteriormente:
/*
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
*/int random(int max){
srand((unsigned) time(NULL));return(rand()% max)+1;}
Este código no es bueno. Llamar srand()cada vez que quiera llamar rand()es una idea terrible. Como time()normalmente devuelve un valor en segundos, llamar a esta función rápidamente devolverá el mismo valor "aleatorio".
Blastfurnace
3
Esta función se confundiría con la random()función de Unix .
srand
: por qué llamarlo solo una vez .Respuestas:
Editar : en Linux, es posible que prefiera usar aleatorio y srandom .
fuente
time()
solo cambia una vez por segundo. Si inicia desdetime()
, para cada llamada arand()
, obtendrá el mismo valor para cada llamada durante un solo segundo. Pero la razón más importante es que las propiedadesrand()
y funciones como esta se conocen mejor para el caso de uso donde se siembran exactamente una vez por ejecución, y no en cada llamada. Dependiendo de la "aleatoriedad" con propiedades no comprobadas o no probadas conduce a problemas.rand()
generalmente es) sembrar conrand()
, en el mejor de los casos, no tendría ningún efecto, y en el peor de los casos rompería las cualidades conocidas del generador. Este es un tema profundo. Comience leyendo el Capítulo 3 de Knuth Vol. 2 sobre números aleatorios como la mejor introducción a las matemáticas y dificultades.srand((unsigned int)time(NULL));
La
rand()
función en<stdlib.h>
devuelve un entero pseudoaleatorio entre 0 yRAND_MAX
. Puedes usarsrand(unsigned int seed)
para establecer una semilla.Es una práctica común usar el
%
operador en conjunto conrand()
para obtener un rango diferente (aunque tenga en cuenta que esto arroja algo de uniformidad). Por ejemplo:Si realmente te importa la uniformidad, puedes hacer algo como esto:
fuente
%
es el operador de módulo. Le da el resto de una división entera, porx % n
lo que siempre le dará un número entre0
yn - 1
(siemprex
y cuandon
sean positivos). Si todavía lo encuentra confuso, intente escribir un programa quei
cuente de 0 a 100, e imprimai % n
para algunosn
de su elección más pequeños que 100.Si necesita caracteres aleatorios o enteros seguros:
Como se explica en cómo generar de forma segura números aleatorios en varios lenguajes de programación , querrá hacer uno de los siguientes:
randombytes
/dev/urandom
, no/dev/random
. No OpenSSL (u otros PRNG de espacio de usuario).Por ejemplo:
randombytes_uniform()
es criptográficamente seguro e imparcial.fuente
sodium_init()
en algún momento. No te preocupes por el RNG, usa el núcleo.sodium_init()
aunque no sea necesariamente parte de mi ejemplo porque es un detalle importante.Vamos a pasar por esto. Primero usamos la función srand () para sembrar el aleatorizador. Básicamente, la computadora puede generar números aleatorios basados en el número que se alimenta a srand (). Si proporcionó el mismo valor inicial, se generarían los mismos números aleatorios cada vez.
Por lo tanto, tenemos que sembrar el aleatorizador con un valor que siempre esté cambiando. Hacemos esto al darle el valor del tiempo actual con la función time ().
Ahora, cuando llamamos a rand (), se producirá un nuevo número aleatorio cada vez.
fuente
else{ low_num=max_num; hi_num=min_num+1;
2) falla cuandohi_num - low_num > INT_MAX
. 3) Omite valores en la situación raraINT_MAX > hi_num - low_num > RAND_MAX
.hi_num = max_num + 1;
carece de protección contra el desbordamiento.Si necesita números pseudoaleatorios de mejor calidad que los que
stdlib
ofrece, consulte Mersenne Twister . También es más rápido. Las implementaciones de muestra son abundantes, por ejemplo aquí .fuente
La función estándar de C es
rand()
. Es lo suficientemente bueno como para repartir cartas por solitario, pero es horrible. Muchas implementaciones derand()
ciclo a través de una lista corta de números, y los bits bajos tienen ciclos más cortos. La forma en que algunos programas llamanrand()
es horrible, y calcular una buena semilla para pasarsrand()
es difícil.La mejor manera de generar números aleatorios en C es usar una biblioteca de terceros como OpenSSL. Por ejemplo,
¿Por qué tanto código? Otros lenguajes como Java y Ruby tienen funciones para enteros aleatorios o flotantes. OpenSSL solo da bytes aleatorios, así que trato de imitar cómo Java o Ruby los transformaría en enteros o flotantes.
Para los enteros, queremos evitar el sesgo de módulo . Supongamos que tenemos algunos enteros aleatorios de 4 dígitos
rand() % 10000
, perorand()
solo podemos devolver 0 a 32767 (como lo hace en Microsoft Windows). Cada número del 0 al 2767 aparecería con mayor frecuencia que cada número del 2768 al 9999. Para eliminar el sesgo, podemos volver a intentarrand()
mientras el valor esté por debajo de 2768, porque los valores de 30000 de 2768 a 32767 corresponden de manera uniforme a los valores de 10000 de 0 a 9999.Para flotantes, queremos 53 bits aleatorios, porque un
double
contiene 53 bits de precisión (suponiendo que sea un doble IEEE). Si usamos más de 53 bits, obtenemos sesgo de redondeo. Algunos programadores escriben código comorand() / (double)RAND_MAX
, perorand()
pueden devolver solo 31 bits, o solo 15 bits en Windows.OpenSSL se inicia
RAND_bytes()
, tal vez leyendo/dev/urandom
en Linux. Si necesitamos muchos números aleatorios, sería demasiado lento leerlos todos/dev/urandom
, ya que deben copiarse del núcleo. Es más rápido permitir que OpenSSL genere más números aleatorios a partir de una semilla.Más sobre números aleatorios:
srand()
. Mezcla bits de la hora actual, la ID del proceso y algunos punteros, si no puede leer/dev/urandom
.fuente
float
/double
, por lo que he aclarado la pregunta para mantener losint
números para evitar que sea demasiado amplia. Hay otras preguntas que tratan específicamente de Cfloat
/double
valores aleatorios, por lo que puede volver a publicar su segunda mitad de su respuesta a preguntas tales como stackoverflow.com/questions/13408990/...Si su sistema admite la
arc4random
familia de funciones, recomendaría usarlas en lugar de larand
función estándar .La
arc4random
familia incluye:arc4random
devuelve un entero aleatorio sin signo de 32 bits.arc4random_buf
pone contenido aleatorio en su parámetrobuf : void *
. La cantidad de contenido está determinada por elbytes : size_t
parámetro.arc4random_uniform
devuelve un entero aleatorio sin signo de 32 bits que sigue la regla:,0 <= arc4random_uniform(limit) < limit
donde limit también es un entero sin signo de 32 bits.arc4random_stir
lee datos/dev/urandom
y los transfiere paraarc4random_addrandom
aleatorizar adicionalmente su grupo interno de números aleatorios.arc4random_addrandom
es utilizado porarc4random_stir
para llenar su grupo interno de números aleatorios de acuerdo con los datos que se le pasan.Si no tiene estas funciones, pero está en Unix, puede usar este código:
La
urandom_init
función abre el/dev/urandom
dispositivo y coloca el descriptor de archivourandom_fd
.La
urandom
función es básicamente la misma que una llamada arand
, excepto que es más segura y devuelve unlong
(fácilmente modificable).Sin embargo,
/dev/urandom
puede ser un poco lento, por lo que se recomienda que lo use como semilla para un generador de números aleatorios diferente.Si el sistema no tiene una
/dev/urandom
, pero no tienen un/dev/random
archivo o similar, entonces sólo tiene que cambiar la ruta pasó aopen
enurandom_init
. Las llamadas y las API utilizadas enurandom_init
yurandom
son (creo) compatibles con POSIX, y como tal, deberían funcionar en la mayoría, si no en todos los sistemas compatibles con POSIX.Notas: Una lectura de
/dev/urandom
NO se bloqueará si no hay suficiente entropía disponible, por lo que los valores generados en tales circunstancias pueden ser criptográficamente inseguros. Si está preocupado por eso, use/dev/random
, que siempre se bloqueará si no hay suficiente entropía.Si está en otro sistema (es decir, Windows), utilice
rand
o alguna API interna no portátil dependiente de la plataforma específica de Windows.Envoltorio para la función
urandom
,rand
oarc4random
las llamadas:fuente
STL no existe para C. Usted tiene que llamar
rand
, o mejor aún,random
. Estos se declaran en el encabezado de la biblioteca estándarstdlib.h
.rand
es POSIX,random
es una función de especificación BSD.La diferencia entre
rand
yrandom
es querandom
devuelve un número aleatorio de 32 bits mucho más utilizable, yrand
generalmente devuelve un número de 16 bits. Las páginas de manual de BSD muestran que los bits más bajosrand
son cíclicos y predecibles, por lo querand
es potencialmente inútil para números pequeños.fuente
extern int rand(void);
yextern void srand(unsigned int);
.Eche un vistazo a ISAAC (Indirección, Cambio, Acumular, Agregar y Contar). Está distribuido uniformemente y tiene una duración promedio del ciclo de 2 ^ 8295.
fuente
Esta es una buena manera de obtener un número aleatorio entre dos números de su elección.
Salida la primera vez: 39
Salida la segunda vez: 61
Salida la tercera vez: 65
Puede cambiar los valores
randnum
a los números que elija, y generará un número aleatorio para usted entre esos dos números.fuente
Que desea utilizar
rand()
. Nota ( MUY IMPORTANTE ): asegúrese de establecer la semilla para la función rand. Si no lo hace, sus números aleatorios no son realmente aleatorios . Esto es muy, muy, muy importante. Afortunadamente, generalmente puede usar alguna combinación del temporizador de tic del sistema y la fecha para obtener una buena semilla.fuente
FWIW, la respuesta es que sí, hay una
stdlib.h
función llamadarand
; Esta función se ajusta principalmente para la velocidad y la distribución, no para la imprevisibilidad. Casi todas las funciones aleatorias incorporadas para varios lenguajes y marcos usan esta función de manera predeterminada. También hay generadores de números aleatorios "criptográficos" que son mucho menos predecibles, pero funcionan mucho más lentamente. Deben usarse en cualquier tipo de aplicación relacionada con la seguridad.fuente
Con suerte, esto es un poco más aleatorio que solo usar
srand(time(NULL))
.fuente
Bueno, STL es C ++, no C, así que no sé lo que quieres. Sin embargo, si desea C, existen las funciones
rand()
ysrand()
:Ambos son parte de ANSI C. También existe la
random()
función:Pero, por lo que puedo decir,
random()
no es ANSI C. estándar. Una biblioteca de terceros puede no ser una mala idea, pero todo depende de qué tan aleatorio de un número realmente necesite generar.fuente
C Programa para generar números aleatorios entre 9 y 50
En general, podemos generar un número aleatorio entre lowerLimit y upperLimit-1
es decir, lowerLimit es inclusivo o dice r ∈ [lowerLimit, upperLimit)
fuente
rand()
Es la forma más conveniente de generar números aleatorios.También puede obtener un número aleatorio de cualquier servicio en línea como random.org.
fuente
fuente
fuente
En las CPU modernas x86_64, puede usar el generador de números aleatorios de hardware a través de
_rdrand64_step()
Código de ejemplo:
fuente
fuente
Al escuchar una buena explicación de por qué usar
rand()
para producir números aleatorios distribuidos uniformemente en un rango dado es una mala idea, decidí echar un vistazo a lo sesgada que está la salida en realidad. Mi caso de prueba fue el lanzamiento justo de dados. Aquí está el código C:y aquí está su salida:
No sé qué tan uniforme necesita que sean sus números aleatorios, pero lo anterior parece lo suficientemente uniforme para la mayoría de las necesidades.
Editar: sería una buena idea inicializar el PRNG con algo mejor que
time(NULL)
.fuente
Tuve un problema grave con el generador de números pseudoaleatorios en mi aplicación reciente: repetidamente llamé a mi programa C a través de un script pyhton y estaba usando como semilla el siguiente código:
Sin embargo, desde:
man srand
);time
devolverá el mismo valor cada vez.Mi programa generó la misma secuencia de números. Puede hacer 3 cosas para resolver este problema:
mezclar la salida del tiempo con alguna otra información que cambia en las ejecuciones (en mi aplicación, el nombre de la salida):
Solía djb2 como mi función hash.
Aumenta la resolución del tiempo. En mi plataforma,
clock_gettime
estaba disponible, así que lo uso:Use ambos métodos juntos:
La opción 3 le garantiza (hasta donde yo sé) la mejor aleatoriedad inicial, pero puede crear una diferencia solo en aplicaciones muy rápidas. En mi opinión, la opción 2 es una apuesta segura.
fuente
rand()
No debería usarse para datos criptográficos, estoy de acuerdo. Al menos para mí, mi aplicación no incluía datos criptográficos, por lo que para mí estaba bien el método dado.A pesar de todas las sugerencias de personas
rand()
aquí, ¡no querrás usar arand()
menos que tengas que hacerlo! Los números aleatorios querand()
produce a menudo son muy malos. Para citar de la página de manual de Linux:En cuanto a la portabilidad,
random()
también está definida por el estándar POSIX desde hace bastante tiempo.rand()
es anterior, ya apareció en la primera especificación POSIX.1 (IEEE Std 1003.1-1988), mientras querandom()
apareció por primera vez en POSIX.1-2001 (IEEE Std 1003.1-2001), pero el estándar POSIX actual ya es POSIX.1-2008 (IEEE Std 1003.1-2008), que recibió una actualización hace solo un año (IEEE Std 1003.1-2008, edición de 2016). Por lo tanto, consideraríarandom()
que es muy portátil.POSIX.1-2001 también introdujo las funciones
lrand48()
ymrand48()
, ver aquí :Y una fuente pseudoaleatoria bastante buena es la
arc4random()
función que está disponible en muchos sistemas. No forma parte de ningún estándar oficial, apareció en BSD alrededor de 1997, pero puede encontrarlo en sistemas como Linux y macOS / iOS.fuente
random()
no existe en Windowsrand()
ya que también lo requiere el estándar C. Para cualquier otra cosa, necesita una solución especial solo para Windows, como de costumbre.#ifdef _WIN32
es la frase que verá con mayor frecuencia en el código multiplataforma que desea admitir Windows y, por lo general, hay una solución que funciona con todos los sistemas y una que solo se requiere para Windows.Para aplicaciones Linux C:
Este es mi código modificado de una respuesta anterior que sigue mis prácticas de código C y devuelve un búfer aleatorio de cualquier tamaño (con los códigos de retorno adecuados, etc.). Asegúrese de llamar
urandom_open()
una vez al comienzo de su programa.fuente
Mi solución minimalista debería funcionar para números aleatorios en el rango
[min, max)
. Úselosrand(time(NULL))
antes de invocar la función.fuente
Intente esto, lo puse a partir de algunos de los conceptos ya mencionados anteriormente:
fuente
srand()
cada vez que quiera llamarrand()
es una idea terrible. Comotime()
normalmente devuelve un valor en segundos, llamar a esta función rápidamente devolverá el mismo valor "aleatorio".random()
función de Unix .