171

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

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

The problem with the code I have is that every time I compile and run it, it always generates the same numbers. So my question is what other functions in the random library can accomplish this while being truly random?

For my particular use case, I was trying to get a value within the range [1, 10]

smac89
  • 39,374
  • 15
  • 132
  • 179
  • 3
    This question is bordering dangerously on "primarily opinion based." If you can get rid of the solicitation for opinion, I can see this question being very useful (if it hasn't already been asked). – John Dibling Oct 29 '13 at 18:03
  • 5
    I suggest using a `std::mt19937` as the engine unless you have a good reason not to. And the distribution is a closed interval on both ends. – chris Oct 29 '13 at 18:04
  • @chris What is the syntax for setting that up? And how do I use it to generate random numbers in the specified range? – smac89 Oct 29 '13 at 18:07
  • Extending what @chris said, especially do not use `std::default_random_engine` as you don't have any sort of guarantees about what engine this is. – Robert Allan Hennigan Leahy Oct 29 '13 at 18:13
  • 6
    See http://stackoverflow.com/q/7114043/420683 and http://stackoverflow.com/q/16536617/420683 and http://stackoverflow.com/q/11817493/420683 and http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful – dyp Oct 29 '13 at 18:13
  • 2
    @chris the distribution is not closed on both ends, check this [link](http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution) or this [link](http://www.cplusplus.com/reference/random/uniform_real_distribution/) – memo1288 Oct 29 '13 at 18:29
  • @memo1288 Indeed, you're right. cppreference confused me by stating that `b` was the *maximum* value (a maximum is typically included in the set); my eyes were too tired to distinguish the `)` from a `]` at cplusplus. Checking the Standard confirms: it is a half-open range for `uniform_real_distribution` – dyp Oct 29 '13 at 18:41
  • 1
    @memo1288, Thank you, I thought the OP was using a `std::uniform_int_distribution`, which *is* closed on both ends. – chris Oct 29 '13 at 20:54

6 Answers6

253

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:

#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));
Community
  • 1
  • 1
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • 3
    Since the question is asking for the most general way to generate random numbers you might wanna just use `default_random_engine`, according to c++ primer it is the one that the implementation has deemed most useful – aaronman Oct 29 '13 at 18:56
  • 3
    @aaronman: I'm going by STL's talk, where he explicitly doesn't like that `default_random_engine` exists. – Bill Lynch Oct 29 '13 at 18:57
  • Maybe not for experts but for general use I don't think everyone should have to know the difference between different complex random engines just to use one, if you have no clue why your using `mt19937` why would you use it – aaronman Oct 29 '13 at 18:59
  • I can't get that to compile, it throws an exception on the constructor of `rd`. Does that depend on the compiler, or what could be causing this? (using mingw) It is throwing `what(): random_device::random_device(const std::string&)` – memo1288 Oct 29 '13 at 19:00
  • @memo1288: I'm seeing differing reports. It's possible that you are running an older mingw that doesn't support it. I'd recommend upgrading if that's the case. – Bill Lynch Oct 29 '13 at 19:06
  • 2
    @aaronman, At least with an mt19937, you know you're getting something good. It's like defaulting to `std::vector` in almost all cases. If you know what you need and what the other containers offer, you can make an informed decision, but we tell people to use a vector all the time, even if they don't know what all the different container types are. To be fair, there's no `std::default_container`, but to me, it seems like a similar situation. – chris Oct 29 '13 at 20:58
  • 5
    @chris we all know the difference between a vector and a map, not everyone knows the difference between mt19937 and ranlux24, if someone managed to become a programmer without knowing what a vector and a dictionary are maybe they should have a `std::default_container`, hopefully there are no people considering themselves programmers that don't know the differences, a lot of scripting languages have a default map type structure, which could be implemented in a whole variety of ways that the user may not know – aaronman Oct 29 '13 at 21:04
  • 23
    The `nextafter` call is overkill for most applications. The chances of a random `double` landing exactly on the endpoint are so minuscule that there's no practical difference between including and excluding it. – Mark Ransom Jun 27 '14 at 17:00
  • 4
    @chris Unrelated (but you opened the door), your `std::vector` analogy doesn't work here because `std::vector` *is* actually a good default due to CPU caching. It even outperforms `std::list` for insertion in the middle. That's true even if you do understand all the containers and could make an informed decision based on algorithmic complexity. – void.pointer Oct 23 '14 at 22:53
  • @void.pointer That depends. If it costs 1e6 cycles to make a copy of something, and 1e2 cycles when you go out to main memory, there's a collection size tipping point where list is better. It's only when copying is cheaper than a cache miss that it matters. Unilateral declarations are *always wrong*. Except that one, of course. :P – Mark Storer Dec 06 '19 at 14:34
  • Like all optimizations, everything must be measured. And instead of treating my advice as unilateral, treat it as a very useful best practice or guiding principle. – void.pointer Dec 06 '19 at 17:03
  • @MarkRansom You will often want to use it though. For stress tests and other types of randomized tests, if you want to generate precise random input within required bounds. In probability theory, the chance of landing on the upper bound is 0%, but in reality you only have N possible values between your lower and upper bound which are generated with uniform distribution. I have landed on the upper bound many many times when running millions of tests, and for that reason, some of the tests have even failed. With complex algorithms you want to eliminate false positives that cause you to debug. – Snackoverflow Dec 25 '20 at 10:23
  • @anddero if you want to test against the limits, don't wait for the random number to generate them - you could be waiting forever. Just test with those explicit values. – Mark Ransom Dec 25 '20 at 16:41
  • @MarkRansom True. However, testing against the limits does not replace the requirement of your code doing exactly what is expected. If your function states it will generate a random number in range `[a; b)`, it should do so precisely, not relying on the low probability of `b` occurring. It *will* produce occasional errors in live applications, which are practically unrepeatable, therefore undebuggable and unfixable, but will cause a serious headache. – Snackoverflow Dec 25 '20 at 22:07
  • Can the uniform_real_distribution be created and destroyed at any time without consequence? Or is it like seeding, where doing it more than once is actually bad? Or would each creation give the same outputs each time? – Tyler Shellberg Apr 19 '21 at 15:32
  • @TylerShellberg: [Looking at libcxx's implementation](https://github.com/llvm-mirror/libcxx/blob/master/include/random), it seems like the implementation is really light weight, and that there would be minimal to zero concern with constructing one many times. – Bill Lynch Apr 19 '21 at 15:48
33

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

effolkronium
  • 523
  • 4
  • 10
11

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

Ingo Mi
  • 999
  • 12
  • 26
0

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;
}

~

Bimo
  • 5,987
  • 2
  • 39
  • 61
0

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>);
khanh
  • 600
  • 5
  • 20
-4

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.

Malcolm McLean
  • 6,258
  • 1
  • 17
  • 18
  • 3
    Except that isn't uniform (0 to N-1). The reason is easy, let's suppose N=100 and RAND_MAX = 32758. There is not a way to uniformely map 32758 elements (RAND_MAX) to 100 inputs. The unique way is set a bound on 32000 and re-execute rand() if gets out of bounds – amchacon Nov 13 '16 at 11:03
  • 2
    If N is 100 then your RNG must be extremely good to be able to detect the deviation from a flat distribution. – Malcolm McLean Mar 13 '17 at 00:43