¿Cómo generar un número aleatorio en C ++?

Intento hacer un juego con dados, y necesito tener números aleatorios (para simular los lados del dado. Sé cómo hacerlo entre 1 y 6). Utilizando

#include  #include  #include  using namespace std; int main() { srand((unsigned)time(0)); int i; i = (rand()%6)+1; cout << i << "\n"; } 

no funciona muy bien, porque cuando ejecuto el progtwig varias veces, aquí está la salida que obtengo:

 6 1 1 1 1 1 2 2 2 2 5 2 

Así que quiero un comando que genere un número aleatorio diferente cada vez, no el mismo 5 veces seguidas. ¿Hay algún comando que haga esto?

El problema más importante de su aplicación de prueba es que llame a srand una vez y luego llame al rand una vez y salga.

El objective de la función srand es inicializar la secuencia de números pseudoaleatorios con una semilla aleatoria. Significa que si pasas el mismo valor a srand en dos aplicaciones diferentes (con la misma implementación de srand / rand ) obtendrás exactamente la misma secuencia de valores rand() leídos después de eso. Pero su secuencia pseudoaleatoria consta de un solo elemento: su salida consiste en los primeros elementos de diferentes secuencias pseudoaleatorias sembradas con tiempo de precisión de 1 segundo. Entonces, ¿qué esperas ver? Cuando ejecutas la aplicación en el mismo segundo, tu resultado es el mismo por supuesto (como Martin York ya mencionó en un comentario a la respuesta).

En realidad, debes llamar a srand(seed) una vez y luego llamar a rand() muchas veces y analizar esa secuencia: debe verse al azar.

El uso de módulo puede introducir un sesgo en los números aleatorios, dependiendo del generador de números aleatorios. Vea esta pregunta para más información. Por supuesto, es perfectamente posible obtener números repetitivos en una secuencia aleatoria.

Pruebe algunas características de C ++ 11 para una mejor distribución:

 #include  #include  int main() { std::mt19937 rng; rng.seed(std::random_device()()); std::uniform_int_distribution dist6(1,6); // distribution in range [1, 6] std::cout < < dist6(rng) << std::endl; } 

Consulte esta pregunta / respuesta para obtener más información sobre C ++ 11 números aleatorios. Lo anterior no es la única manera de hacer esto, pero es de una manera.

Si está utilizando libs de impulso , puede obtener un generador aleatorio de esta manera:

 #include  #include  // Used in randomization #include  #include  #include  #include  using namespace std; using namespace boost; int current_time_nanoseconds(){ struct timespec tm; clock_gettime(CLOCK_REALTIME, &tm); return tm.tv_nsec; } int main (int argc, char* argv[]) { unsigned int dice_rolls = 12; random::mt19937 rng(current_time_nanoseconds()); random::uniform_int_distribution<> six(1,6); for(unsigned int i=0; i 

Donde la función current_time_nanoseconds() da la hora actual en nanosegundos que se usa como una semilla.


Aquí hay una clase más general para obtener enteros y fechas aleatorias en un rango:

 #include  #include  #include  #include  #include  #include "boost/date_time/posix_time/posix_time.hpp" #include "boost/date_time/gregorian/gregorian.hpp" using namespace std; using namespace boost; using namespace boost::posix_time; using namespace boost::gregorian; class Randomizer { private: static const bool debug_mode = false; random::mt19937 rng_; // The private constructor so that the user can not directly instantiate Randomizer() { if(debug_mode==true){ this->rng_ = random::mt19937(); }else{ this->rng_ = random::mt19937(current_time_nanoseconds()); } }; int current_time_nanoseconds(){ struct timespec tm; clock_gettime(CLOCK_REALTIME, &tm); return tm.tv_nsec; } // C++ 03 // ======== // Dont forget to declare these two. You want to make sure they // are unacceptable otherwise you may accidentally get copies of // your singleton appearing. Randomizer(Randomizer const&); // Don't Implement void operator=(Randomizer const&); // Don't implement public: static Randomizer& get_instance(){ // The only instance of the class is created at the first call get_instance () // and will be destroyed only when the program exits static Randomizer instance; return instance; } bool method() { return true; }; int rand(unsigned int floor, unsigned int ceil){ random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil); return (rand_(rng_)); } // Is not considering the millisecons time_duration rand_time_duration(){ boost::posix_time::time_duration floor(0, 0, 0, 0); boost::posix_time::time_duration ceil(23, 59, 59, 0); unsigned int rand_seconds = rand(floor.total_seconds(), ceil.total_seconds()); return seconds(rand_seconds); } date rand_date_from_epoch_to_now(){ date now = second_clock::local_time().date(); return rand_date_from_epoch_to_ceil(now); } date rand_date_from_epoch_to_ceil(date ceil_date){ date epoch = ptime(date(1970,1,1)).date(); return rand_date_in_interval(epoch, ceil_date); } date rand_date_in_interval(date floor_date, date ceil_date){ return rand_ptime_in_interval(ptime(floor_date), ptime(ceil_date)).date(); } ptime rand_ptime_from_epoch_to_now(){ ptime now = second_clock::local_time(); return rand_ptime_from_epoch_to_ceil(now); } ptime rand_ptime_from_epoch_to_ceil(ptime ceil_date){ ptime epoch = ptime(date(1970,1,1)); return rand_ptime_in_interval(epoch, ceil_date); } ptime rand_ptime_in_interval(ptime floor_date, ptime ceil_date){ time_duration const diff = ceil_date - floor_date; long long gap_seconds = diff.total_seconds(); long long step_seconds = Randomizer::get_instance().rand(0, gap_seconds); return floor_date + seconds(step_seconds); } }; 
 #include  #include  #include  int main() { srand(time(NULL)); int random_number = std::rand(); // rand() return a number between ​0​ and RAND_MAX std::cout < < random_number; return 0; } 

http://en.cppreference.com/w/cpp/numeric/random/rand

Aquí hay una solución. Cree una función que devuelva el número aleatorio y colóquelo fuera de la función principal para hacerlo global. Espero que esto ayude

 #include  #include  #include  int rollDie(); using std::cout; int main (){ srand((unsigned)time(0)); int die1; int die2; for (int n=10; n>0; n--){ die1 = rollDie(); die2 = rollDie(); cout < < die1 << " + " << die2 << " = " << die1 + die2 << "\n"; } system("pause"); return 0; } int rollDie(){ return (rand()%6)+1; } 

Genere un número aleatorio diferente cada vez, no el mismo seis veces seguidas.

Caso de uso

Comparé el problema de Predictabilidad con una bolsa de seis pedazos de papel, cada uno con un valor de 0 a 5 escrito en él. Se extrae un trozo de papel de la bolsa cada vez que se requiere un nuevo valor. Si la bolsa está vacía, los números vuelven a colocarse en la bolsa.

… a partir de esto, puedo crear un tipo de algoritmo.

Algoritmo

Una bolsa es generalmente una Collection . Elegí un bool[] (también conocido como matriz booleana, plano de bits o bitmap) para tomar el rol de la bolsa.

La razón por la que elegí un bool[] es porque el índice de cada elemento ya es el valor de cada hoja de papel. Si los documentos requieren algo más escrito en ellos, entonces habría utilizado un Dictionary en su lugar. El valor booleano se utiliza para realizar un seguimiento de si el número se ha dibujado o no.

Un contador llamado RemainingNumberCount se inicializa a 5 que cuenta hacia abajo cuando se elige un número aleatorio. Esto nos ahorra tener que contar cuántos pedazos de papel quedan cada vez que deseamos dibujar un nuevo número.

Para seleccionar el siguiente valor aleatorio, estoy usando un for..loop para buscar en la bolsa de índices, y un contador para contar cuando un index es false llamado NumberOfMoves .

NumberOfMoves se utiliza para elegir el siguiente número disponible. NumberOfMoves se establece primero como un valor aleatorio entre 0 y 5 , porque hay 0..5 pasos disponibles que podemos realizar a través de la bolsa. En la siguiente iteración, NumberOfMoves se establece como un valor aleatorio entre 0 y 4 , porque ahora hay 0..4 pasos que podemos hacer a través de la bolsa. A medida que se usan los números, los números disponibles se reducen, por lo que usamos rand() % (RemainingNumberCount + 1) para calcular el siguiente valor para NumberOfMoves .

Cuando el contador NumberOfMoves llega a cero, el for..loop debe ser el siguiente:

  1. Establezca el valor actual para que sea el mismo que para el índice for..loop .
  2. Establezca todos los números en la bolsa a false .
  3. Descanso del para … for..loop .

Código

El código para la solución anterior es el siguiente:

(ponga los siguientes tres bloques en el archivo principal .cpp uno después del otro)

 #include "stdafx.h" #include  #include  #include  class RandomBag { public: int Value = -1; RandomBag() { ResetBag(); } void NextValue() { int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers); int NumberOfMoves = rand() % (RemainingNumberCount + 1); for (int i = 0; i < BagOfNumbersLength; i++) if (BagOfNumbers[i] == 0) { NumberOfMoves--; if (NumberOfMoves == -1) { Value = i; BagOfNumbers[i] = 1; break; } } if (RemainingNumberCount == 0) { RemainingNumberCount = 5; ResetBag(); } else RemainingNumberCount--; } std::string ToString() { return std::to_string(Value); } private: bool BagOfNumbers[6]; int RemainingNumberCount; int NumberOfMoves; void ResetBag() { RemainingNumberCount = 5; NumberOfMoves = rand() % 6; int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers); for (int i = 0; i < BagOfNumbersLength; i++) BagOfNumbers[i] = 0; } }; 

Una clase de consola

Creo esta clase de consola porque facilita la redirección de la salida.

Debajo en el código ...

 Console::WriteLine("The next value is " + randomBag.ToString()); 

...puede ser reemplazado por...

 std::cout < < "The next value is " + randomBag.ToString() << std::endl; 

... y luego esta clase de Console se puede eliminar si lo desea.

 class Console { public: static void WriteLine(std::string s) { std::cout < < s << std::endl; } }; 

Método principal

Ejemplo de uso de la siguiente manera:

 int main() { srand((unsigned)time(0)); // Initialise random seed based on current time RandomBag randomBag; Console::WriteLine("First set of six...\n"); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); Console::WriteLine("\nSecond set of six...\n"); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); Console::WriteLine("\nThird set of six...\n"); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); randomBag.NextValue(); Console::WriteLine("The next value is " + randomBag.ToString()); Console::WriteLine("\nProcess complete.\n"); system("pause"); } 

Ejemplo de salida

Cuando ejecuté el progtwig, obtuve el siguiente resultado:

 First set of six... The next value is 2 The next value is 3 The next value is 4 The next value is 5 The next value is 0 The next value is 1 Second set of six... The next value is 3 The next value is 4 The next value is 2 The next value is 0 The next value is 1 The next value is 5 Third set of six... The next value is 4 The next value is 5 The next value is 2 The next value is 0 The next value is 3 The next value is 1 Process complete. Press any key to continue . . . 

Frase de cierre

Este progtwig fue escrito usando Visual Studio 2017 , y elegí convertirlo en un proyecto de Visual C++ Windows Console Application usando .Net 4.6.1 .

No estoy haciendo nada especial aquí, por lo que el código también debería funcionar en versiones anteriores de Visual Studio.

para al azar cada archivo RUN

 size_t randomGenerator(size_t min, size_t max) { std::mt19937 rng; rng.seed(std::random_device()()); //rng.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count()); std::uniform_int_distribution dist(min, max); return dist(rng); } 

Aquí hay un generador aleatorio simple con aprox. probabilidad igual de generar valores positivos y negativos alrededor de 0:

  int getNextRandom(const size_t lim) { int nextRand = rand() % lim; int nextSign = rand() % lim; if (nextSign < lim / 2) return -nextRand; return nextRand; } int main() { srand(time(NULL)); int r = getNextRandom(100); cout << r << endl; return 0; } 

Este código produce números aleatorios de n a m .

 int random(int n, int m){ return rand() % (m - n + 1) + n; } 

ejemplo:

 int main(){ srand(time(0)); for(int i = 0; i < 10; i++) cout << random(0, 99); }