How do I generate a random number using the C++11

2019-01-13 21:29发布

The new C++11 Standard has a whole chapter dedicated to random number generators. But how do I perform the simplest, most common task that used to be coded like this, but without resorting to the standard C library:

srand((unsigned int)time(0));
int i = rand();

Are there reasonable defaults for random-number engines, distributions, and seeds that one could use out of the box?

标签: c++ random c++11
7条回答
forever°为你锁心
2楼-- · 2019-01-13 21:41

You should be able to do something like:

std::default_random_engine e((unsigned int)time(0));
int i = e();

The quality of the default_random_engine is implementation dependent. You could also use std::min_rand0 or std::min_rand.

Probably a better way to seed a random engine is with as true a random number as is available from the implementation rather than use time.

E.g.

std::random_device rd;
std::default_random_engine e( rd() );
查看更多
Rolldiameter
3楼-- · 2019-01-13 21:42

I use the following code in my project. 'engine' and 'distribution' can be one of the provided by the library.

#include <random>
#include <functional>
#include <iostream>
...
std::uniform_int_distribution<unsigned int> unif;
std::random_device rd;
std::mt19937 engine(rd());
std::function<unsigned int()> rnd = std::bind(unif, engine);

std::cout << rnd() << '\n';
查看更多
迷人小祖宗
4楼-- · 2019-01-13 21:42

Random number generation is a difficult problem. There is no truly random way to do it. If you are just generating randomness to seed a game environment then your approach should be fine. rand() has several shortcomings.

If you are needing randomness to generate encryption keys then you're S.O.L. The best way in that case is to go out to the operating system, which usually has mechanism. On POSIX that's random() (or read from /dev/random if you're so disposed). On Windows you can use the CryptoAPI:

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

查看更多
可以哭但决不认输i
5楼-- · 2019-01-13 21:43

If your existing code was appropriate before the new standard, then it will continue to be. The new random number generators were added for applications which require a higher quality of pseudo-randomness, e.g. stochastic simulation.

查看更多
乱世女痞
6楼-- · 2019-01-13 21:45

You could use RC4 to generate random bytes. This probably has the properties that you want. It is fast and fairly simple to implement. The sequence is repeatable across all implementations when the seed is known, and completely unpredictable when the seed is not known. http://en.wikipedia.org/wiki/RC4

查看更多
SAY GOODBYE
7楼-- · 2019-01-13 21:47

Unifying and simplifying some of the samples already provided I will summarize to:

// Good random seed, good engine
auto rnd1 = std::mt19937(std::random_device{}());

// Good random seed, default engine
auto rnd2 = std::default_random_engine(std::random_device{}());

// like rnd1, but force distribution to int32_t range
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));

// like rnd3, but force distribution across negative numbers as well
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

Then I ran some tests to see what the defaults look like:

#include <random>
#include <functional>
#include <limits>
#include <iostream>

template<class Func>
void print_min_mean_max(Func f) {
   typedef decltype(f()) ret_t;
   ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min();
   uint64_t total = 0, count = 10000000;
   for (uint64_t i = 0; i < count; ++i) {
      auto res = f();
      min = std::min(min,res);
      max = std::max(max,res);
      total += res;
   }
   std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl;
}

int main() {
   auto rnd1 = std::mt19937(std::random_device{}());
   auto rnd2 = std::default_random_engine(std::random_device{}());

   auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
   auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

   print_min_mean_max(rnd1);
   print_min_mean_max(rnd2);
   print_min_mean_max(rnd3);
   print_min_mean_max(rnd4);
}

Produces the output:

min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978

So as we can see, mt19937 and default_random_engine have a different default range, so use of uniform_int_distribution is advised.

Also, default uniform_int_distribution is [0, max_int] (non-negative), even when using a signed integer type. Must provide range explicitly if you want full range.

Finally, its important to remember this at times like these.

查看更多
登录 后发表回答