随机数生成,两种不同的方法?

时间:2020-08-07 17:53:40

标签: c++ c++11

有人知道以下代码中使用的两种随机数生成方法之间的区别吗?我怀疑第一种情况在计算上可能会更昂贵,因为每次生成随机数时,它都会从/dev/urandom获取新种子。如果我在这些示例中正确生成了随机数,也请多加评论。

我很困惑,因为uniform_int_distribution指定了template<class URNG> result_type operator()(URNG& g);,在某些示例中,我看到传递的参数类型为default_random_engine,而其他时候为random_device。这使default_random_engine的实际操作更加混乱。

例如,方法1我见过:

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

方法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;
}

2 个答案:

答案 0 :(得分:3)

第一种方法是不好的做法,第二种是首选。尽管在第二种方法中,通常不建议使用default_random_engine,除非它是出于实验或其他一些不重要的原因。主要原因是实现定义的,因此它会根据编译器而有所不同,并且通常根本不健壮,只是简单。

第一种方法不好的原因是std::random_device轮询硬件的真实随机性来源。这是有限的供应。更好的做法是将其用作伪随机数生成器(PRNG)的完全不可预测的种子。这就是第二个示例更好的原因。

我对您的第二个示例进行了一些更改。主要变化是,我不需要声明random_device就可以坐在堆栈上,而我使用的是std::mt19937,这可能是C ++代码中最常见的PRNG。

没有C ++标准库PRNG被认为足以满足加密目的;您需要一个外部库。

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

答案 1 :(得分:1)

std库提供一组Predefined random number generators,该集合为生成的值提供了一定的保证。其中之一是default_random_engine,它是实现定义的(因此您需要检查库的供应商如何实现它)。

要拥有可靠的生成器(不同供应商之间的结果一致),您可以选择mt19937之类的其他之一。

random_device获得的随机数通常仅用作所选随机数生成器的种子。对于random_device,您遇到的问题与default_random_engine类似,因为未指定如何生成值。

其背后的想法是,random_device通常为种子提供足够好的值,但对于适当的生成器来说不够好。

如果您知道程序运行所在的特定硬件以及该库,并且知道random_device根据良好的来源创建随机数,则可以选择这样做,但是如果您创建的应用程序用于不同的操作系统和未知的硬件,那么random_device将不会成为生成器。