How to generate a random number in C++?

后端 未结 11 1529
萌比男神i
萌比男神i 2020-11-22 11:14

I\'m trying to make a game with dice, and I need to have random numbers in it (to simulate the sides of the die. I know how to make it between 1 and 6). Using



        
11条回答
  •  没有蜡笔的小新
    2020-11-22 11:40

    Whenever you do a basic web search for random number generation in the C++ programming language this question is usually the first to pop up! I want to throw my hat into the ring to hopefully better clarify the concept of pseudo-random number generation in C++ for future coders that will inevitably search this same question on the web!

    The Basics

    Pseudo-random number generation involves the process of utilizing a deterministic algorithm that produces a sequence of numbers whose properties approximately resemble random numbers. I say approximately resemble, because true randomness is a rather elusive mystery in mathematics and computer science. Hence, why the term pseudo-random is utilized to be more pedantically correct!

    Before you can actually use a PRNG, i.e., pseudo-random number generator, you must provide the algorithm with an initial value often referred too as the seed. However, the seed must only be set once before using the algorithm itself!

    /// Proper way!
    seed( 1234 ) /// Seed set only once...
    for( x in range( 0, 10) ):
      PRNG( seed ) /// Will work as expected
    
    /// Wrong way!
    for( x in rang( 0, 10 ) ):
      seed( 1234 ) /// Seed reset for ten iterations!
      PRNG( seed ) /// Output will be the same...
    

    Thus, if you want a good sequence of numbers, then you must provide an ample seed to the PRNG!

    The Old C Way

    The backwards compatible standard library of C that C++ has, uses what is called a linear congruential generator found in the cstdlib header file! This PRNG functions through a discontinuous piecewise function that utilizes modular arithmetic, i.e., a quick algorithm that likes to use the modulo operator '%'. The following is common usage of this PRNG, with regards to the original question asked by @Predictability:

    #include 
    #include 
    #include 
    
    int main( void )
    {
      int low_dist  = 1;
      int high_dist = 6;
      std::srand( ( unsigned int )std::time( nullptr ) );
      for( int repetition = 0; repetition < 10; ++repetition )
        std::cout << low_dist + std::rand() % ( high_dist - low_dist ) << std::endl;
      return 0;
    }
    

    The common usage of C's PRNG houses a whole host of issues such as:

    1. The overall interface of std::rand() isn't very intuitive for the proper generation of pseudo-random numbers between a given range, e.g., producing numbers between [1, 6] the way @Predictability wanted.
    2. The common usage of std::rand() eliminates the possibility of a uniform distribution of pseudo-random numbers, because of the Pigeonhole Principle.
    3. The common way std::rand() gets seeded through std::srand( ( unsigned int )std::time( nullptr ) ) technically isn't correct, because time_t is considered to be a restricted type. Therefore, the conversion from time_t to unsigned int is not guaranteed!

    For more detailed information about the overall issues of using C's PRNG, and how to possibly circumvent them, please refer to Using rand() (C/C++): Advice for the C standard library’s rand() function!

    The Standard C++ Way

    Since the ISO/IEC 14882:2011 standard was published, i.e., C++11, the random library has been apart of the C++ programming language for a while now. This library comes equipped with multiple PRNGs, and different distribution types such as: uniform distribution, normal distribution, binomial distribution, etc. The following source code example demonstrates a very basic usage of the random library, with regards to @Predictability's original question:

    #include 
    #include 
    #include 
    
    using u32    = uint_least32_t; 
    using engine = std::mt19937;
    
    int main( void )
    {
      std::random_device os_seed;
      const u32 seed = os_seed();
    
      engine generator( seed );
      std::uniform_int_distribution< u32 > distribute( 1, 6 );
    
      for( int repetition = 0; repetition < 10; ++repetition )
        std::cout << distribute( generator ) << std::endl;
      return 0;
    }
    

    The 32-bit Mersenne Twister engine, with a uniform distribution of integer values was utilized in the above example. (The name of the engine in source code sounds weird, because its name comes from its period of 2^19937-1 ). The example also uses std::random_device to seed the engine, which obtains its value from the operating system (If you are using a Linux system, then std::random_device returns a value from /dev/urandom).

    Take note, that you do not have to use std::random_device to seed any engine. You can use constants or even the chrono library! You also don't have to use the 32-bit version of the std::mt19937 engine, there are other options! For more information about the capabilities of the random library, please refer to cplusplus.com

    All in all, C++ programmers should not use std::rand() anymore, not because its bad, but because the current standard provides better alternatives that are more straight forward and reliable. Hopefully, many of you find this helpful, especially those of you who recently web searched generating random numbers in c++!

提交回复
热议问题