如何使用C++ 11标准库生成随机数

Bar*_*ski 23 c++ random c++11

新的C++ 11标准有一整章专门用于随机数生成器.但是,我如何执行过去像这样编码的最简单,最常见的任务,但不使用标准C库:

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

是否可以使用开箱即用的随机数引擎,分布和种子的合理默认值?

CB *_*ley 30

你应该可以这样做:

std::default_random_engine e((unsigned int)time(0));
int i = e();
Run Code Online (Sandbox Code Playgroud)

default_random_engine依赖于实现的质量.你也可以使用std::min_rand0std::min_rand.

种子随机引擎的一种更好的方法可能是从实现中获得的随机数,而不是使用time.

例如

std::random_device rd;
std::default_random_engine e( rd() );
Run Code Online (Sandbox Code Playgroud)

  • 信息:这个答案与OP的例子之间的最大区别在于编码器控制引擎状态的位置:它在"e"中.在OP的代码中,状态被隐藏为`rand`中的静态数据.在处理多线程程序时,这是一个重要的区别.`rand`必须有某种保护才能使其安全.`default_random_engine`没有.如果要从多个线程调用它,可以在外部自己提供同步机制.这意味着如果您不需要同步它,`default_random_engine`可以更快. (8认同)

mmo*_*cny 6

统一和简化已经提供的一些样本我将总结:

// 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{}()));
Run Code Online (Sandbox Code Playgroud)

然后我运行了一些测试来查看默认值是什么样的:

#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);
}
Run Code Online (Sandbox Code Playgroud)

产生输出:

min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978
Run Code Online (Sandbox Code Playgroud)

我们可以看到,mt19937和default_random_engine具有不同的默认范围,因此建议使用uniform_int_distribution.

此外,默认的uniform_int_distribution是[0,max_int](非负),即使使用有符号整数类型也是如此.如果您想要全范围,必须明确提供范围.

最后,重要的是有时要记住这些.

  • 值得注意的是,有一个64位版本的`std :: mt19937`:`std :: mt19937_64`,每次调用返回64位随机性.`auto rnd5 = std :: mt19937_64(std :: random_device {}()); // min:4879020137534 mean:1655417118684 max:18446741225191893648` (2认同)