Genere números aleatorios uniformemente en un rango completo

Necesito generar números aleatorios dentro de un intervalo específico, [max; min].

Además, los números aleatorios deben distribuirse uniformemente durante el intervalo, no ubicados en un punto particular.

Currenly estoy generando como:

for(int i=0; i<6; i++) { DWORD random = rand()%(max-min+1) + min; } 

De mis pruebas, los números aleatorios se generan alrededor de un punto solamente.

 Example min = 3604607; max = 7654607; 

Números aleatorios generados:

 3631594 3609293 3630000 3628441 3636376 3621404 

De las respuestas a continuación: OK, RAND_MAX es 32767. Estoy en la plataforma C ++ de Windows. ¿Hay algún otro método para generar números aleatorios con una distribución uniforme?

Por qué rand es una mala idea

La mayoría de las respuestas que obtuvo aquí utilizan la función rand y el operador de módulo. Ese método puede no generar números de manera uniforme (depende del rango y el valor de RAND_MAX ) y, por lo tanto, se desaconseja.

C ++ 11 y generación en un rango

Con C ++ 11, muchas otras opciones han aumentado. Una de ellas se ajusta a sus requisitos, para generar un número aleatorio en un rango, muy bien: std::uniform_int_distribution . Aquí hay un ejemplo:

 const int range_from = 0; const int range_to = 10; std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution distr(range_from, range_to); std::cout << distr(generator) << '\n'; 

Y aquí está el ejemplo stream.

Otros generadores aleatorios

El encabezado ofrece innumerables otros generadores de números aleatorios con diferentes tipos de distribuciones, incluyendo Bernoulli, Poisson y normal.

¿Cómo puedo barajar un contenedor?

El estándar proporciona std::random_shuffle , que se puede usar de la siguiente manera:

 std::vector vec = {4, 8, 15, 16, 23, 42}; std::random_device random_dev; std::mt19937 generator(random_dev()); std::shuffle(vec.begin(), vec.end(), generator); 

El algoritmo reordenará los elementos al azar, con una complejidad lineal.

Boost.Random

Otra alternativa, en caso de que no tenga acceso a un comstackdor C ++ 11+ , es usar Boost.Random . Su interfaz es muy similar a la de C ++ 11.

[edit] Advertencia: No use rand() para estadísticas, simulación, criptografía o cualquier cosa seria.

Es lo suficientemente bueno para hacer que los números parezcan aleatorios para un humano típico a toda prisa, nada más.

Consulte la respuesta de @ Jefffrey para obtener mejores opciones, o esta respuesta para números aleatorios criptográficos.


En general, los bits altos muestran una mejor distribución que los bits bajos, por lo que la forma recomendada de generar números aleatorios de un rango para fines simples es:

 ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min 

Nota : asegúrese de que RAND_MAX + 1 no se desborde (¡gracias Demi)!

La división genera un número aleatorio en el intervalo [0, 1); “estirar” esto al rango requerido. Solo cuando max-min + 1 se acerca a RAND_MAX necesita una función “BigRand ()” como la publicada por Mark Ransom.

Esto también evita algunos problemas de corte debido al módulo, lo que puede empeorar aún más tus números.


No se garantiza que el generador de números aleatorios incorporado tenga la calidad requerida para las simulaciones estadísticas. Está bien que los números “parezcan aleatorios” a un ser humano, pero para una aplicación seria, debes tomar algo mejor, o al menos verificar sus propiedades (la distribución uniforme suele ser buena, pero los valores tienden a correlacionarse, y la secuencia es determinista ) Knuth tiene un tratado excelente (aunque difícil de leer) sobre generadores de números aleatorios, y recientemente encontré que LFSR es excelente y muy fácil de implementar, dado que sus propiedades son buenas para usted.

Si RAND_MAX es 32767, puede duplicar fácilmente el número de bits.

 int BigRand() { assert(INT_MAX/(RAND_MAX+1) > RAND_MAX); return rand() * (RAND_MAX+1) + rand(); } 

Me gustaría complementar las excelentes respuestas de Angry Shoe y peterchen con una breve descripción del estado del arte en 2015:

Algunas buenas elecciones

randutils

La biblioteca de randutils (presentación) es una novedad interesante, que ofrece una interfaz simple y (declarada) capacidades robustas aleatorias. Tiene las desventajas de que agrega una dependencia de su proyecto y, al ser nuevo, no se ha probado exhaustivamente. De todos modos, siendo libre (licencia de MIT) y encabezado solo, creo que vale la pena intentarlo.

Muestra mínima: una tirada de dado

 #include  #include "randutils.hpp" int main() { randutils::mt19937_rng rng; std::cout << rng.uniform(1,6) << "\n"; } 

Incluso si uno no está interesado en la biblioteca, el sitio web ( http://www.pcg-random.org/ ) ofrece muchos artículos interesantes sobre el tema de la generación de números aleatorios en general y la biblioteca C ++ en particular.

Boost.Random

Boost.Random (documentación) es la biblioteca que inspiró C ++ 11, con quien comparte gran parte de la interfaz. Aunque teóricamente también es una dependencia externa, Boost tiene ahora un estado de biblioteca "cuasi-estándar", y su módulo Random podría considerarse como la opción clásica para la generación de números aleatorios de buena calidad. Presenta dos ventajas con respecto a la solución C ++ 11:

  • es más portátil, solo necesita compatibilidad de comstackdor para C ++ 03
  • su random_device usa métodos específicos del sistema para ofrecer siembra de buena calidad

El único pequeño inconveniente es que el módulo que ofrece el random_device no es solo de encabezado, uno tiene que comstackr y vincular boost_random .

Muestra mínima: una tirada de dado

 #include  #include  #include  int main() { boost::random::random_device rand_dev; boost::random::mt19937 generator(rand_dev()); boost::random::uniform_int_distribution<> distr(1, 6); std::cout << distr(generator) << '\n'; } 

Si bien la muestra mínima funciona bien, los progtwigs reales deberían usar un par de mejoras:

  • make mt19937 a thread_local : el generador es bastante regordete (> 2 KB) y es mejor no asignarlo en la stack
  • seed mt19937 con más de un entero: Mersenne Twister tiene un gran estado y puede beneficiarse de más entropía durante la inicialización

Algunas elecciones no tan buenas

La biblioteca C ++ 11

Si bien es la solución más idiomática, la biblioteca no ofrece mucho a cambio de la complejidad de su interfaz, incluso para las necesidades básicas. El error está en std::random_device : el estándar no std::random_device ninguna calidad mínima para su salida (siempre que entropy() devuelva 0 ) y, a partir de 2015, MinGW (no el comstackdor más utilizado, pero difícilmente una opción esotérica) siempre imprimirá 4 en la muestra mínima.

Muestra mínima: una tirada de dado

 #include  #include  int main() { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution distr(1, 6); std::cout << distr(generator) << '\n'; } 

Si la implementación no está podrida, esta solución debería ser equivalente a la de Boost y se aplican las mismas sugerencias.

La solución de Godot

Muestra mínima: una tirada de dado

 #include  #include  int main() { std::cout << std::randint(1,6); } 

Esta es una solución simple, efectiva y ordenada. Solo defecto, tardará un tiempo en comstackrse: unos dos años, siempre que C ++ 17 se libere a tiempo y la función experimental randint esté aprobada en el nuevo estándar. Quizás en ese momento también mejorarán las garantías sobre la calidad de la siembra.

La peor solución es mejor

Muestra mínima: una tirada de dado

 #include  #include  #include  int main() { std::srand(std::time(nullptr)); std::cout << (std::rand() % 6 + 1); } 

La antigua solución C se considera dañina, y por buenas razones (consulte las otras respuestas aquí o este análisis detallado ). Aún así, tiene sus ventajas: es simple, portátil, rápido y honesto, en el sentido en que se sabe que los números aleatorios que uno obtiene no son dignos, y por lo tanto uno no está tentado de usarlos para propósitos serios.

La solución de troll contable

Muestra mínima: una tirada de dado

 #include  int main() { std::cout << 9; // http://dilbert.com/strip/2001-10-25 } 

Mientras que 9 es un resultado algo inusual para una tirada de dado regular, uno tiene que admirar la excelente combinación de buenas cualidades en esta solución, que se las arregla para ser la más rápida, más simple, más amigable con la caché y más portátil. Sustituyendo 9 por 4 se obtiene un generador perfecto para cualquier tipo de mazmorras y dragones mueren, mientras se evitan los valores cargados de símbolos 1, 2 y 3. El único pequeño error es que, debido al mal genio de los trols de contabilidad de Dilbert, este progtwig en realidad engendra un comportamiento indefinido.

Si puede, use Boost . He tenido buena suerte con su biblioteca al azar .

uniform_int debería hacer lo que quieras.

Si le preocupa la aleatoriedad y no la velocidad, debe usar un método seguro de generación de números aleatorios. Hay varias maneras de hacer esto … La más fácil es usar el generador de números aleatorios de OpenSSL .

También puede escribir su propio uso de un algoritmo de encriptación (como AES ). Al elegir una semilla y una IV y luego volver a cifrar continuamente la salida de la función de cifrado. Usar OpenSSL es más fácil, pero menos varonil.

Debería mirar RAND_MAX para su comstackdor / entorno particular. Creo que vería estos resultados si rand () está produciendo un número aleatorio de 16 bits. (Parece que asumes que será un número de 32 bits).

No puedo prometer que esta es la respuesta, pero publique su valor de RAND_MAX y un poco más de detalles sobre su entorno.

Comprueba qué RAND_MAX está en tu sistema: supongo que solo son 16 bits y tu scope es demasiado grande.

Más allá de eso, vea esta discusión sobre: Generar enteros aleatorios dentro de un rango deseado y las notas sobre el uso (o no) de la función C rand () .

Si desea que los números se distribuyan uniformemente en el rango, debe dividir su rango en varias secciones iguales que representen la cantidad de puntos que necesita. Luego obtenga un número aleatorio con un min / max para cada sección.

Como otra nota, probablemente no deberías usar rand () ya que no es muy bueno para generar números aleatorios. No sé en qué plataforma se está ejecutando, pero probablemente haya una función mejor a la que pueda llamar como random ().

Este no es el código, pero esta lógica puede ayudarte.

 static double rnd(void) { return (1.0/(RAND_MAX+1.0)*((double)(rand())) ); } static void InitBetterRnd(unsigned int seed) { register int i; srand( seed ); for( i=0; i 

Esto debería proporcionar una distribución uniforme en el rango [low, high) sin usar flotadores, siempre que el rango general sea menor que RAND_MAX.

 uint32_t rand_range_low(uint32_t low, uint32_t high) { uint32_t val; // only for 0 < range <= RAND_MAX assert(low < high); assert(high - low <= RAND_MAX); uint32_t range = high-low; uint32_t scale = RAND_MAX/range; do { val = rand(); } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range return val/scale + low; } 

y para valores superiores a RAND_MAX quieres algo como

 uint32_t rand_range(uint32_t low, uint32_t high) { assert(high>low); uint32_t val; uint32_t range = high-low; if (range < RAND_MAX) return rand_range_low(low, high); uint32_t scale = range/RAND_MAX; do { val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval } while (val >= range); return val + low; } 

Esto es más o menos cómo std :: uniform_int_distribution hace las cosas.

Por su naturaleza, una pequeña muestra de números aleatorios no tiene que estar uniformemente distribuida. Son al azar, después de todo. Estoy de acuerdo en que si un generador de números aleatorios está generando números que aparecen consistentemente agrupados, entonces probablemente haya algo erróneo en él.

Pero tenga en cuenta que la aleatoriedad no es necesariamente uniforme.

Editar: agregué “pequeña muestra” para aclarar.

La solución dada por man 3 rand para un número entre 1 y 10 inclusive es:

 j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0))); 

En tu caso, sería:

 j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0))); 

Por supuesto, esto no es una aleatoriedad o uniformidad perfecta, como señalan algunos otros mensajes, pero esto es suficiente para la mayoría de los casos.

@Solution ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

Advertencia : no olvide que debido a los estiramientos y posibles errores de precisión (incluso si RAND_MAX fuera lo suficientemente grande), solo podrá generar “contenedores” distribuidos uniformemente y no todos los números en [min, max].


@Solución: Bigrand

Advertencia : Tenga en cuenta que esto duplica los bits, pero aún así no podrá generar todos los números en su rango en general, es decir, no es necesariamente cierto que BigRand () generará todos los números en su rango.


Información : Su enfoque (módulo) está “bien” siempre que el rango de rand () exceda su rango de intervalo y rand () sea “uniforme”. El error para, como máximo, los primeros números máximos – min es 1 / (RAND_MAX +1).

Además, sugiero cambiar al nuevo paquete aleatorio e en C ++ 11 también, que ofrece mejores y más variedades de implementaciones que rand ().

Acabo de encontrar esto en Internet. Esto debería funcionar:

 DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));