Reputation: 2180
Does anyone know the differences between the two methods of random number generation used in the following code? My suspicion is the first case may be more computationally expensive because it's getting a new seed from /dev/urandom
every time a random number is generated. Also appreciate any comments if I'm generating random numbers correctly in these examples.
I'm confused because uniform_int_distribution specifies template<class URNG> result_type operator()(URNG& g);
and in some examples I see the parameter passed to be of the type default_random_engine and other time random_device. This adds confusion to what default_random_engine
actually does.
For example, method 1 I have seen:
#include <iostream>
#include <random>
#include <map>
using namespace std;
int main()
{
random_device rd;
uniform_int_distribution<int> p{0,9};
map<int,int> m;
for (int i=0; i < 100; ++i) {
m[p(rd)]++;
}
for (map<int,int>::iterator it = m.begin();
it != m.end(); ++it)
cout << it->first << ", " << it->second << '\n';
return 0;
}
Method 2,
#include <iostream>
#include <random>
#include <map>
using namespace std;
int main()
{
random_device rd;
default_random_engine gen(rd());
uniform_int_distribution<int> p{0,9};
map<int,int> m;
for (int i=0; i < 100; ++i) {
m[p(gen)]++;
}
for (map<int,int>::iterator it = m.begin();
it != m.end(); ++it)
cout << it->first << ", " << it->second << '\n';
return 0;
}
Upvotes: 0
Views: 106
Reputation: 40842
The std library offers a set of Predefined random number generators that gives certain guarantees about the values generated. One of them is default_random_engine
which is implementation-defined (so you need to check how the vendor of the library implemented it).
To have a reliable generator (consistent results between the different vendors) you would choose one of the others like mt19937
.
The random numbers you get from random_device
are normally only used as a seed for the chosen random number generator. For random_device
you have a similar problem as with default_random_engine
as it is not specified how the values are generated.
The idea behind this is that random_device
provides good enough values for a seed in general but not for not good enough for a proper generator.
If you know the specific hardware your program is running on and the library, and you know that random_device
creates random numbers based on a good source, then it might be an option, but if you create an application that is used on different OS and unknown hardware, then random_device
won't be an option as a generator.
Upvotes: 1
Reputation: 5202
The first method is bad practice, and the second is preferred. Although, in the second method, default_random_engine
is typically not recommended unless it's for experimenting or some other non-important reason. The big reason is that's implementation-defined, so it will differ based on compiler, and it generally is not robust at all, just simple.
The reasoning that the first method is bad is that std::random_device
polls your hardware's source of true randomness. This is a limited supply. The better practice is to use it as a completely unpredictable seed to a pseudo-random number generator (PRNG). This is why the second example is better.
I've made a couple changes to your second example. The main change is that I don't need to declare a random_device
to sit around on the stack, and I use std::mt19937
which is probably the most common PRNG you'll see in C++ code.
None of the C++ Standard Library PRNGs are considered sufficient for cryptographic purposes; you'd need an external library for that.
#include <iostream>
#include <map>
#include <random>
int main() {
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<int> p{0, 9};
std::map<int, int> m;
for (int i = 0; i < 100; ++i) {
m[p(gen)]++;
}
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ", " << it->second << '\n';
}
return 0;
}
Upvotes: 3