使用随机类和时间种子 (NULL),均匀分布始终给出相同的第一个输出,即使使用不同的编译,但在第一个输出之后的行为与您期望的伪随机数生成器的行为相同。
这是构造出来的,还是我使用不当?
MWE:
#include <ctime>
#include <iostream>
#include <random>
using namespace std;
default_random_engine gen(time(NULL));
uniform_int_distribution<int> dist(10,200);
int main()
{
for(int i = 0; i < 5; i++)
cout<<dist(gen)<<endl;
return 0;
}
我运行这个程序的前三次得到的输出是:
57
134
125
136
112
在第二次尝试之前,我决定删除 uniform_int_distribution
和 int main()
之间的空行,看看种子是否基于编译时间,如您所见,那没关系。
57
84
163
42
146
再次运行:
57
73
181
160
46
所以在我的运行中,我总是先得到 57
,这当然不是世界末日,如果我想要不同的输出,我可以丢弃第一个输出。但这是否是设计使然(如果是,为什么?)还是我是否以某种方式滥用了生成器(如果是,如何?)。
最佳答案
我不确定出了什么问题(现在!),但您仍然可以按如下方式按时间初始化而不会遇到问题(借自 here)。
#include <ctime>
#include <iostream>
#include <random>
#include <chrono>
using namespace std;
unsigned seed1 = std::chrono::system_clock::now().time_since_epoch().count();
default_random_engine gen(seed1); //gen(time(NULL));
uniform_int_distribution<int> dist(10,200);
int main()
{
for(int i = 0; i < 5; i++)
cout<<dist(gen)<<endl;
return 0;
}
您还可以使用不确定的随机设备(它从您的击键、鼠标移动和其他来源窃取时间信息以生成不可预测的数字)。这是您可以选择的最强种子,但如果您不需要强有力的保证,计算机时钟是更好的选择,因为如果您经常使用它,计算机可能会耗尽“随机性”(需要多次击键和鼠标运动来产生一个真正的随机数)。
std::random_device rd;
default_random_engine gen(rd());
运行
cout<<time(NULL)<<endl;
cout<<std::chrono::system_clock::now().time_since_epoch().count()<<endl;
cout<<rd()<<endl;
在我的机器上生成
1413844318
1413844318131372773
3523898368
因此 chrono
库提供了比 ctime
库大得多且变化更快的数字(以纳秒为单位)。 random_device
正在生成遍布 map 的不确定数字。所以似乎 ctime
正在生成的种子可能以某种方式靠得太近,因此部分映射到相同的内部状态?
我做了另一个程序,看起来像这样:
#include <iostream>
#include <random>
using namespace std;
int main(){
int oldval = -1;
unsigned int oldseed = -1;
cout<<"Seed\tValue\tSeed Difference"<<endl;
for(unsigned int seed=0;seed<time(NULL);seed++){
default_random_engine gen(seed);
uniform_int_distribution<int> dist(10,200);
int val = dist(gen);
if(val!=oldval){
cout<<seed<<"\t"<<val<<"\t"<<(seed-oldseed)<<endl;
oldval = val;
oldseed = seed;
}
}
}
如您所见,这只是打印出当前时间之前每个可能的随机种子的第一个输出值,以及具有相同值的种子和先前种子的数量。输出的摘录如下所示:
Seed Value Seed Difference
0 10 1
669 11 669
1338 12 669
2007 13 669
2676 14 669
3345 15 669
4014 16 669
4683 17 669
5352 18 669
6021 19 669
6690 20 669
7359 21 669
8028 22 669
8697 23 669
9366 24 669
10035 25 669
10704 26 669
11373 27 669
12042 28 669
12711 29 669
13380 30 669
14049 31 669
因此对于每个新的第一个数字,有 669 个种子给出了第一个数字。因为第二个和第三个数字不同,我们仍然在生成唯一的内部状态。我认为我们必须更多地了解 default_random_engine
才能了解 669(可以分解为 3 和 223)的特殊之处。
鉴于此,很清楚为什么 chrono
和 random_device
库工作得更好:它们生成的种子总是相差 669 以上。请记住,即使第一个数字相同,在许多程序中重要的是不同生成的数字序列。
关于c++ - 伪随机数生成器给出相同的第一个输出,但随后按预期运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26475595/