使用随机类和时间种子(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;
}
Run Code Online (Sandbox Code Playgroud)
前三次我运行这个程序我得到的输出:
57
134
125
136
112
Run Code Online (Sandbox Code Playgroud)
在第二次尝试之前,我决定删除之间的空行uniform_int_distribution
,int main()
只是为了查看种子是否基于编译时间,如您所见,这无关紧要.
57
84
163
42
146
Run Code Online (Sandbox Code Playgroud)
再跑一次:
57
73
181
160
46
Run Code Online (Sandbox Code Playgroud)
所以在我的跑步中我一直是57
第一个,这当然不是世界末日,如果我想要不同的输出我可以扔掉第一个输出.但是,这是否是设计(如果是这样,为什么?)或者我是否在某种程度上滥用发生器(如果是这样的话怎么样?)就会产生疑问.
我不确定会出现什么问题(但是!),但你仍然可以按照以下方式初始化,而不会遇到问题(从这里借来).
#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;
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用非确定性的随机设备(它会从您的击键,鼠标移动和其他来源窃取计时信息以生成不可预测的数字).这是你可以选择的最强的种子,但是如果你不需要强有力的保证,计算机的时钟是更好的方法,因为如果你经常使用计算机可能会耗尽"随机性"(它需要很多击键和鼠标动作产生一个真正的随机数).
std::random_device rd;
default_random_engine gen(rd());
Run Code Online (Sandbox Code Playgroud)
运行
cout<<time(NULL)<<endl;
cout<<std::chrono::system_clock::now().time_since_epoch().count()<<endl;
cout<<rd()<<endl;
Run Code Online (Sandbox Code Playgroud)
在我的机器上生成
1413844318
1413844318131372773
3523898368
Run Code Online (Sandbox Code Playgroud)
所以该chrono
库提供了比库更大的数字和更快速的数字(以纳秒为单位)ctime
.的random_device
是生产这些都是在地图上不确定性的数字.所以似乎种子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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,这只是打印出每个可能的随机种子的第一个输出值,直到当前时间以及具有相同值的种子和先前种子的数量.输出的摘录如下所示:
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
Run Code Online (Sandbox Code Playgroud)
因此,对于每个新的第一个数字,有669个种子给出第一个数字.因为第二个和第三个数字不同,我们仍然会产生独特的内部状态.我认为我们必须更多地了解它default_random_engine
以了解669的特殊之处(可以将其分解为3和223).
鉴于此,很明显为什么chrono
和random_device
库更好地工作:它们产生的种子总是超过669.请记住,即使第一个数字是相同的,在许多程序中重要的是由不同的数字生成的数字序列.