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

时间:2011-08-27 22:28:09

标签: c++ random c++11

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

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

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

7 个答案:

答案 0 :(得分:30)

您应该可以执行以下操作:

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

default_random_engine的质量取决于实施方式。您还可以使用std::min_rand0std::min_rand

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

E.g。

std::random_device rd;
std::default_random_engine e( rd() );

答案 1 :(得分: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{}()));

然后我运行了一些测试来查看默认设置:

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

产生输出:

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

正如我们所看到的,mt19937和default_random_engine具有不同的默认范围,因此建议使用uniform_int_distribution。

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

最后,its important to remember this有时会这样。

答案 2 :(得分:2)

如果您的现有代码在新标准之前是合适的,那么它将继续存在。新的随机数发生器被添加用于需要更高质量的伪随机性的应用,例如,随机模拟。

答案 3 :(得分:2)

我在项目中使用以下代码。 '引擎'和'发行'可以是图书馆提供的。

#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 :(得分:2)

你走了。随机双打范围:

// For ints
// replace _real_ with _int_, 
// <double> with <int> and use integer constants

#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>

int main()
{
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100);  //(min, max)

    //get one
    const double random_num = dist(rng);

    //or..
    //print 10 of them, for fun.
    std::generate_n( 
        std::ostream_iterator<double>(std::cout, "\n"), 
        10, 
        [&]{ return dist(rng);} ); 
    return 0;
}

答案 5 :(得分:0)

随机数生成是一个难题。没有真正随机的方法来做到这一点。如果你只是为游戏环境提供随机性,那么你的方法应该没问题。 rand()有几个缺点。

如果您需要随机生成加密密钥,那么您就是S.O.L.在这种情况下,最好的方法是转到通常具有机制的操作系统。在POSIX上,它是随机的()(如果你这么处理,则从/ dev / random读取)。在Windows上,您可以使用CryptoAPI:

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

答案 6 :(得分:0)

您可以使用RC4生成随机字节。这可能具有您想要的属性。它实现起来快速且相当简单。当种子已知时,序列在所有实现中是可重复的,并且当种子未知时完全不可预测。 http://en.wikipedia.org/wiki/RC4