Generate random numbers using C++11 random library

后端 未结 6 722
梦毁少年i
梦毁少年i 2020-11-22 15:13

As the title suggests, I am trying to figure out a way of generating random numbers using the new C++11 library. I have tried it with this code:<

相关标签:
6条回答
  • 2020-11-22 15:20

    Stephan T. Lavavej (stl) from Microsoft did a talk at Going Native about how to use the new C++11 random functions and why not to use rand(). In it, he included a slide that basically solves your question. I've copied the code from that slide below.

    You can see his full talk here: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

    #include <random>
    #include <iostream>
    
    int main() {
        std::random_device rd;
        std::mt19937 mt(rd());
        std::uniform_real_distribution<double> dist(1.0, 10.0);
    
        for (int i=0; i<16; ++i)
            std::cout << dist(mt) << "\n";
    }
    

    We use random_device once to seed the random number generator named mt. random_device() is slower than mt19937, but it does not need to be seeded because it requests random data from your operating system (which will source from various locations, like RdRand for example).


    Looking at this question / answer, it appears that uniform_real_distribution returns a number in the range [a, b), where you want [a, b]. To do that, our uniform_real_distibution should actually look like:

    std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));
    
    0 讨论(0)
  • 2020-11-22 15:27

    Here's something that I just wrote along those lines::

    #include <random>
    #include <chrono>
    #include <thread>
    
    using namespace std;
    
    //==============================================================
    // RANDOM BACKOFF TIME
    //==============================================================
    class backoff_time_t {
      public:
        random_device                      rd;
        mt19937                            mt;
        uniform_real_distribution<double>  dist;
    
        backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}
    
        double rand() {
          return dist(mt);
        }
    };
    
    thread_local backoff_time_t backoff_time;
    
    
    int main(int argc, char** argv) {
       double x1 = backoff_time.rand();
       double x2 = backoff_time.rand();
       double x3 = backoff_time.rand();
       double x4 = backoff_time.rand();
       return 0;
    }
    

    ~

    0 讨论(0)
  • 2020-11-22 15:34

    My 'random' library provide a high convenient wrapper around C++11 random classes. You can do almost all things with a simple 'get' method.

    Examples:

    1. Random number in a range

      auto val = Random::get(-10, 10); // Integer
      auto val = Random::get(10.f, -10.f); // Float point
      
    2. Random boolean

      auto val = Random::get<bool>( ) // 50% to generate true
      auto val = Random::get<bool>( 0.7 ) // 70% to generate true
      
    3. Random value from a std::initilizer_list

      auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
      
    4. Random iterator from iterator range or all container

      auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
      auto it = Random::get( vec ); // return random iterator
      

    And even more things ! Check out the github page:

    https://github.com/effolkronium/random

    0 讨论(0)
  • 2020-11-22 15:41

    I red all the stuff above, about 40 other pages with c++ in it like this and watched the video from Stephan T. Lavavej "STL" and still wasn't sure how random numbers works in praxis so I took a full Sunday to figure out what its all about and how it works and can be used.

    In my opinion STL is right about "not using srand anymore" and he explained it well in the video 2. He also recommend to use:

    a) void random_device_uniform() -- for encrypted generation but slower (from my example)

    b) the examples with mt19937 -- faster, ability to create seeds, not encrypted


    I pulled out all claimed c++11 books I have access to and found f.e. that german Authors like Breymann (2015) still use a clone of

    srand( time( 0 ) );
    srand( static_cast<unsigned int>(time(nullptr))); or
    srand( static_cast<unsigned int>(time(NULL))); or
    

    just with <random> instead of <time> and <cstdlib> #includings - so be careful to learn just from one book :).

    Meaning - that shouldn't be used since c++11 because:

    Programs often need a source of random numbers. Prior to the new standard, both C and C++ relied on a simple C library function named rand. That function produces pseudorandom integers that are uniformly distributed in the range from 0 to a system- dependent maximum value that is at least 32767. The rand function has several problems: Many, if not most, programs need random numbers in a different range from the one produced by rand. Some applications require random floating-point numbers. Some programs need numbers that reflect a nonuniform distribution. Programmers often introduce nonrandomness when they try to transform the range, type, or distribution of the numbers generated by rand. (quote from Lippmans C++ primer fifth edition 2012)


    I finally found a the best explaination out of 20 books in Bjarne Stroustrups newer ones - and he should know his stuff - in "A tour of C++ 2019", "Programming Principles and Practice Using C++ 2016" and "The C++ Programming Language 4th edition 2014" and also some examples in "Lippmans C++ primer fifth edition 2012":

    And it is really simple because a random number generator consists of two parts: (1) an engine that produces a sequence of random or pseudo-random values. (2) a distribution that maps those values into a mathematical distribution in a range.


    Despite the opinion of Microsofts STL guy, Bjarne Stroustrups writes:

    In , the standard library provides random number engines and distributions (§24.7). By default use the default_random_engine , which is chosen for wide applicability and low cost.

    The void die_roll() Example is from Bjarne Stroustrups - good idea generating engine and distribution with using (more bout that here).


    To be able to make practical use of the random number generators provided by the standard library in <random> here some executable code with different examples reduced to the least necessary that hopefully safe time and money for you guys:

        #include <random>     //random engine, random distribution
        #include <iostream>   //cout
        #include <functional> //to use bind
    
        using namespace std;
    
    
        void space() //for visibility reasons if you execute the stuff
        {
           cout << "\n" << endl;
           for (int i = 0; i < 20; ++i)
           cout << "###";
           cout << "\n" << endl;
        }
    
        void uniform_default()
        {
        // uniformly distributed from 0 to 6 inclusive
            uniform_int_distribution<size_t> u (0, 6);
            default_random_engine e;  // generates unsigned random integers
    
        for (size_t i = 0; i < 10; ++i)
            // u uses e as a source of numbers
            // each call returns a uniformly distributed value in the specified range
            cout << u(e) << " ";
        }
    
        void random_device_uniform()
        {
             space();
             cout << "random device & uniform_int_distribution" << endl;
    
             random_device engn;
             uniform_int_distribution<size_t> dist(1, 6);
    
             for (int i=0; i<10; ++i)
             cout << dist(engn) << ' ';
        }
    
        void die_roll()
        {
            space();
            cout << "default_random_engine and Uniform_int_distribution" << endl;
    
        using my_engine = default_random_engine;
        using my_distribution = uniform_int_distribution<size_t>;
    
            my_engine rd {};
            my_distribution one_to_six {1, 6};
    
            auto die = bind(one_to_six,rd); // the default engine    for (int i = 0; i<10; ++i)
    
            for (int i = 0; i <10; ++i)
            cout << die() << ' ';
    
        }
    
    
        void uniform_default_int()
        {
           space();
           cout << "uniform default int" << endl;
    
           default_random_engine engn;
           uniform_int_distribution<size_t> dist(1, 6);
    
            for (int i = 0; i<10; ++i)
            cout << dist(engn) << ' ';
        }
    
        void mersenne_twister_engine_seed()
        {
            space();
            cout << "mersenne twister engine with seed 1234" << endl;
    
            //mt19937 dist (1234);  //for 32 bit systems
            mt19937_64 dist (1234); //for 64 bit systems
    
            for (int i = 0; i<10; ++i)
            cout << dist() << ' ';
        }
    
    
        void random_seed_mt19937_2()
        {
            space();
            cout << "mersenne twister split up in two with seed 1234" << endl;
    
            mt19937 dist(1234);
            mt19937 engn(dist);
    
            for (int i = 0; i < 10; ++i)
            cout << dist() << ' ';
    
            cout << endl;
    
            for (int j = 0; j < 10; ++j)
            cout << engn() << ' ';
        }
    
    
    
        int main()
        {
                uniform_default(); 
                random_device_uniform();
                die_roll();
                random_device_uniform();
                mersenne_twister_engine_seed();
                random_seed_mt19937_2();
            return 0;
        }
    

    I think that adds it all up and like I said, it took me a bunch of reading and time to destill it to that examples - if you have further stuff about number generation I am happy to hear about that via pm or in the comment section and will add it if necessary or edit this post. Bool

    0 讨论(0)
  • 2020-11-22 15:43

    Here is some resource you can read about pseudo-random number generator.

    https://en.wikipedia.org/wiki/Pseudorandom_number_generator

    Basically, random numbers in computer need a seed (this number can be the current system time).

    Replace

    std::default_random_engine generator;
    

    By

    std::default_random_engine generator(<some seed number>);
    
    0 讨论(0)
  • 2020-11-22 15:46

    You've got two common situations. The first is that you want random numbers and aren't too fussed about the quality or execution speed. In that case, use the following macro

    #define uniform() (rand()/(RAND_MAX + 1.0))
    

    that gives you p in the range 0 to 1 - epsilon (unless RAND_MAX is bigger than the precision of a double, but worry about that when you come to it).

    int x = (int) (uniform() * N);

    Now gives a random integer on 0 to N -1.

    If you need other distributions, you have to transform p. Or sometimes it's easier to call uniform() several times.

    If you want repeatable behaviour, seed with a constant, otherwise seed with a call to time().

    Now if you are bothered about quality or run time performance, rewrite uniform(). But otherwise don't touch the code. Always keep uniform() on 0 to 1 minus epsilon. Now you can wrap the C++ random number library to create a better uniform(), but that's a sort of medium-level option. If you are bothered about the characteristics of the RNG, then it's also worth investing a bit of time to understand how the underlying methods work, then provide one. So you've got complete control of the code, and you can guarantee that with the same seed, the sequence will always be exactly the same, regardless of platform or which version of C++ you are linking to.

    0 讨论(0)
提交回复
热议问题