有人知道以下代码中使用的两种随机数生成方法之间的区别吗?我怀疑第一种情况在计算上可能会更昂贵,因为每次生成随机数时,它都会从/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;
}
答案 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
将不会成为生成器。