Those three lines of generating random number looks a bit tricky. It is hard to always remember those lines. Could someone please shed some light on it to make it easier to understand?
#include <random>
#include <iostream>
int main()
{
std::random_device rd; //1st line: Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //2nd line: Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' '; //3rd line: Use dis to transform the random unsigned int generated by gen into an int in [1, 6]
std::cout << '\n';
}
Here are some questions I can think of:
1st line of code:
random_device is a class as described by the documentation random_device, so this line means declaring a object rd? If yes, why in 2nd line we pass rd() to construct mt19937 instead of using the object rd (without parentheses)?
3rd line of code:
Why do call class uniform_int_distribution<> object dis()? Is dis() a function? Why shall we pass in gen object into dis()?
random_device is slow but genuinely random, it's used to generate the 'seed' for the random number sequence.
mt19937 is fast but only 'pseudo random'. It needs a 'seed' to start generating a sequence of numbers. That seed can be random (as in your example) so you get a different sequence of random numbers each time. But it could be a constant, so you get the same sequence of numbers each time.
uniform_int_distribution is a way of mapping random numbers (which could have any values) to the numbers you're actually interested in, in this case a uniform distribution of integers from 1 to 6.
As is often the case with OO programming, this code is about division of responsibilities. Each class contributes a small piece to the overall requirement (the generation of dice rolls). If you wanted to do something different it's easy because you've got all the pieces in front of you.
If this is too much then all you need to do is write a function to capture the overall effect, for instance
int dice_roll()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> dis(1, 6);
return dis(gen);
}
dis is an example of a function object or functor. It's an object which overloads operator() so it can be called as if it was a function.
std::random_device rd; // create access to truly random numbers
std::mt19937 gen{rd()}; // create pseudo random generator.
// initialize its seed to truly random number.
std::uniform_int_distribution<> dis{1, 6}; // define distribution
...
auto x = dis(gen); // generate pseudo random number form `gen`
// and transform its result to desired distribution `dis`.
Related
I'm trying to generate a random number using rand() command, but each time i get very similar numbers.
This is my code:
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
srand(time(0));
cout << rand();
return 0;
}
I ran it 5 times and the numbers i got are:
21767
21806
21836
21862
21888
How can i make the numbers be more different?
From the documentation of rand:
There are no guarantees as to the quality of the random sequence produced. In the past, some implementations of rand() have had serious shortcomings in the randomness, distribution and period of the sequence produced (in one well-known example, the low-order bit simply alternated between 1 and 0 between calls).
rand() is not recommended for serious random-number generation needs. It is recommended to use C++11's random number generation facilities to replace rand().
It (and I) recommend to use the newer c++11 random number generators in <random>.
In your specific case it seems you want a std::uniform_int_distribution. An example, as given on the linked page is:
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(1, RAND_MAX);
std::cout << distrib(gen) << '\n';
I am trying to generate a random number in c++ using a modern approach.However i get the same random number every time i call the function
int getRandomPixel() {
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
std::uniform_int_distribution<> distr(0, 255); // define the range
return distr(eng);
}
Your std::random_device is a PRNG, as stated on cppreference:
std::random_device may be implemented in terms of an
implementation-defined pseudo-random number engine if a
non-deterministic source (e.g. a hardware device) is not available to
the implementation. In this case each std::random_device object may
generate the same number sequence.
On each call of getRandomPixel() you recreate the rd which will then produce the same first seed each time which will in turn produce the same value when your mt19937 is seeded with that value because that's recreated as well and thus has the same initial state.
You should not recreate them each call:
int getRandomPixel() {
static std::random_device rd; // obtain a random number from hardware
static std::mt19937 eng(rd()); // seed the generator
static std::uniform_int_distribution<> distr(0, 255); // define the range
return distr(eng);
}
The following solves the problem.I believe the issue was that i was recreating the device and the generator in every call
using u16 = unsigned short int;
u16 getRandomPixel() {
static std::random_device rd; // obtain a random number from hardware
static std::mt19937 eng(rd()); // seed the generator
std::uniform_int_distribution<u16> distr(0, 255); // define the range
return distr(eng);
}
I am given to believe that random number generators (RNGs) should only be seeded once to ensure that the distribution of results is as intended.
I am writing a Monte Carlo simulation in C++ which consists of a main function ("A") calling another function ("B") several times, where a large quantity of random numbers is generated in B.
Currently, I am doing the following in B:
void B(){
std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;
std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
std::mt19937 eng(seq);
std::uniform_real_distribution<> randU(0,1);
double myRandNum = randU(eng);
//do stuff with my random number
}
As you can see, I am creating a new random number generator each time I call the function B. This, as far as I can see, is a waste of time - the RNG can still generate a lot more random numbers!
I have experimented with making "eng" extern but this generates an error using g++:
error: ‘eng’ has both ‘extern’ and initializer extern std::mt19937 eng(seq);
How can I make the random number generator "global" so that I can use it many times?
Be careful with one-size-fits-all rules. 'Globals are evil' is one of them. A RNG should be a global object. (Caveat: each thread should get its own RNG!) I tend to wrap mine in a singleton map, but simply seeding and warming one up at the beginning of main() suffices:
std::mt19937 rng;
int main()
{
// (seed global object 'rng' here)
rng.dispose(10000); // warm it up
For your usage scenario (generating multiple RNs per call), you shouldn't have any problem creating a local distribution for each function call.
One other thing: std::random_device is not your friend -- it can throw at any time for all kinds of stupid reasons. Make sure to wrap it up in a try..catch block. Or, and I recommend this, use a platform specific way to get a true random number. (On Windows, use the Crypto API. On everything else, use /dev/urandom/.)
Hope this helps.
You shouldn't need to pass anything or declare anything, as the interaction between mt19937 and uniform_real_distribution is through globals.
std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;
std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
std::mt19937 eng(seq);
B()
...
void B()
{
std::uniform_real_distribution<> randU(0,1);
...
I'm working on implementing R code into C++ so that it runs faster, but I am having difficulties implementing mersenne twister. I only wish to generate values between (0,1). Here is what I have that pertains to this question.
#include <random>
std::mt19937 generator (123);
std::cout << "Random value: " << generator() << std:: endl;
I tried dividing by RAND_MAX, but that did not produce the values that I was looking for.
Thanks in advance.
In C++11 the concepts of "(pseudo) random generator" and "probability distribution" are separated, and for good reasons.
What you want can be achieved with the following lines:
std::mt19937 generator (123);
std::uniform_real_distribution<double> dis(0.0, 1.0);
double randomRealBetweenZeroAndOne = dis(generator);
If you want to understand why this separation is necessary, and why using a standard division /range manipulation on the output of the generator is a bad idea, watch this video.
You may want to consider code like this:
// For pseudo-random number generators and distributions
#include <random>
...
// Use random_device to generate a seed for Mersenne twister engine.
std::random_device rd{};
// Use Mersenne twister engine to generate pseudo-random numbers.
std::mt19937 engine{rd()};
// "Filter" MT engine's output to generate pseudo-random double values,
// **uniformly distributed** on the closed interval [0, 1].
// (Note that the range is [inclusive, inclusive].)
std::uniform_real_distribution<double> dist{0.0, 1.0};
// Generate pseudo-random number.
double x = dist(engine);
For more details on generating pseudo-random numbers in C++ (including reasons why rand() is not good), see this video by Stephan T. Lavavej (from Going Native 2013):
rand() Considered Harmful
std::mt19937 does not generate between 0 and RAND_MAX like rand(), but between 0 and 2^32-1
And by the way, the class provides min() and max() values!
You need to convert the value to a double, substract min() and divide by max()-min()
uint32_t val;
val << generator;
double doubleval = ((double)val - generator::min())/(generator::max()-generator::min());
or (less generic)
uint32_t val;
val << generator;
double doubleval = (double)val * (1.0 / std::numeric_limits<std::uint32_t>::max());
I've read that many pseudo-random number generators require many samples in ordered to be "warmed up". Is that the case when using std::random_device to seed std::mt19937, or can we expect that it's ready after construction? The code in question:
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
Mersenne Twister is a shift-register based pRNG (pseudo-random number generator) and is therefore subject to bad seeds with long runs of 0s or 1s that lead to relatively predictable results until the internal state is mixed up enough.
However the constructor which takes a single value uses a complicated function on that seed value which is designed to minimize the likelihood of producing such 'bad' states. There's a second way to initialize mt19937 where you directly set the internal state, via an object conforming to the SeedSequence concept. It's this second method of initialization where you may need to be concerned about choosing a 'good' state or doing warmup.
The standard includes an object conforming to the SeedSequence concept, called seed_seq. seed_seq takes an arbitrary number of input seed values, and then performs certain operations on these values in order to produce a sequence of different values suitable for directly setting the internal state of a pRNG.
Here's an example of loading up a seed sequence with enough random data to fill the entire std::mt19937 state:
std::array<int, 624> seed_data;
std::random_device r;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 eng(seq);
This ensures that the entire state is randomized. Also, each engine specifies how much data it reads from the seed_sequence so you may want to read the docs to find that info for whatever engine you use.
Although here I load up the seed_seq entirely from std::random_device, seed_seq is specified such that just a few numbers that aren't particularly random should work well. For example:
std::seed_seq seq{1, 2, 3, 4, 5};
std::mt19937 eng(seq);
In the comments below Cubbi indicates that seed_seq works by performing a warmup sequence for you.
Here's what should be your 'default' for seeding:
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 rng(seed);
If you seed with just one 32-bit value, all you will ever get is one of the same 2^32 trajectories through state-space. If you use a PRNG with KiBs of state, then you should probably seed all of it. As described in the comments to #bames63' answer, using std::seed_seq is probably not a good idea if you want to init the whole state with random numbers. Sadly, std::random_device does not conform to the SeedSequence concept, but you can write a wrapper that does:
#include <random>
#include <iostream>
#include <algorithm>
#include <functional>
class random_device_wrapper {
std::random_device *m_dev;
public:
using result_type = std::random_device::result_type;
explicit random_device_wrapper(std::random_device &dev) : m_dev(&dev) {}
template <typename RandomAccessIterator>
void generate(RandomAccessIterator first, RandomAccessIterator last) {
std::generate(first, last, std::ref(*m_dev));
}
};
int main() {
auto rd = std::random_device{};
auto seedseq = random_device_wrapper{rd};
auto mt = std::mt19937{seedseq};
for (auto i = 100; i; --i)
std::cout << mt() << std::endl;
}
This works at least until you enable concepts. Depending on whether your compiler knows about SeedSequence as a C++20 concept, it may fail to work because we're supplying only the missing generate() method, nothing else. In duck-typed template programming, that code is sufficient, though, because the PRNG does not store the seed sequence object.
I believe there are situations where MT can be seeded "poorly" which results in non-optimal sequences. If I remember correctly, seeding with all zeroes is one such case. I would recommend you try to use the WELL generators if this is a serious issue for you. I believe they are more flexible - the quality of the seed does not matter as much. (Perhaps to answer your question more directly: it's probably more efficient to focus on seeding well as opposed to seeding poorly then trying to generate a bunch of samples to get the generator to an optimal state.)