在Linux中,<random>生成相同的数字,但在Windows中不生成
下面的代码是为了在区间[1,100]中生成五个伪随机数的列表。 我使用time(0)
对default_random_engine
进行种子处理,这会在unix时间返回系统时间 。 当我使用Microsoft Visual Studio 2013在Windows 7上编译和运行此程序时,它按预期工作(请参见下文)。 当我用Arch Linux搭配g ++编译器的时候,它的performance很奇怪。
在Linux中,每次都会生成5个数字。 最后4个数字在每次执行时都会有所不同(通常情况下),但第一个数字将保持不变。
Windows和Linux 5次执行的输出示例:
| Windows: | Linux: --------------------------------------- Run 1 | 54,01,91,73,68 | 25,38,40,42,21 Run 2 | 46,24,16,93,82 | 25,78,66,80,81 Run 3 | 86,36,33,63,05 | 25,17,93,17,40 Run 4 | 75,79,66,23,84 | 25,70,95,01,54 Run 5 | 64,36,32,44,85 | 25,09,22,38,13
除了这个谜之外,Linux上的第一个数字会周期性地增加一个。 在得到上述结果之后,我等了大约30分钟,再次尝试发现第一个数字已经改变,现在总是生成一个26,并且定期递增1,现在是32。随着time(0)
的变化time(0)
。
为什么第一个数字很less在运行中发生变化,然后当它增加1?
代码。 它整齐地打印出5个数字和系统时间:
#include <iostream> #include <random> #include <time.h> using namespace std; int main() { const int upper_bound = 100; const int lower_bound = 1; time_t system_time = time(0); default_random_engine e(system_time); uniform_int_distribution<int> u(lower_bound, upper_bound); cout << '#' << '\t' << "system time" << endl << "-------------------" << endl; for (int counter = 1; counter <= 5; counter++) { int secret = u(e); cout << secret << '\t' << system_time << endl; } system("pause"); return 0; }
这是怎么回事:
-
libstdc ++(GCC的标准库)中的
default_random_engine
是minstd_rand0
,它是一个简单的线性同余引擎:typedef linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
-
这个引擎产生随机数的方式是x i + 1 =(16807x i + 0)mod 2147483647。
-
因此,如果种子是不同的1,那么大部分时间第一次生成的数字将相差16807。
-
这个发生器的范围是[1,2147483646]。 libstdc ++的
uniform_int_distribution
把它映射到[1,100]范围内的一个整数本质上是这样的:生成一个数字n
。 如果数字不大于2147483600,则返回(n - 1) / 21474836 + 1
; 否则,请用新号码重试。应该很容易看出,在绝大多数情况下,只有16807的两个不同的数字在[1,100]这个程序下会产生相同的数字。 实际上,人们可以预计,每21474836/16807 = 1278秒或21.3分钟,生成的数字就会增加1,这与您的观察相符。
MSVC的default_random_engine
是mt19937
,没有这个问题。
std::default_random_engine
是实现定义的。 std::mt19937
使用std::mt19937
或std::mt19937_64
。
另外std::time
和ctime
函数不是很精确,而是使用<chrono>
头文件中定义的types:
#include <iostream> #include <random> #include <chrono> int main() { const int upper_bound = 100; const int lower_bound = 1; auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count(); std::mt19937 e; e.seed(static_cast<unsigned int>(t)); //Seed engine with timed value. std::uniform_int_distribution<int> u(lower_bound, upper_bound); std::cout << '#' << '\t' << "system time" << std::endl << "-------------------" << std::endl; for (int counter = 1; counter <= 5; counter++) { int secret = u(e); std::cout << secret << '\t' << t << std::endl; } system("pause"); return 0; }
在Linux中,随机函数不是概率意义上的随机函数,而是伪随机数发生器。 它被一粒种子腌制,根据那颗种子,产生的数字是伪随机的,均匀分布的。 Linux方式的优点是,在使用来自群体的信息的某些实验的devise中,可以测量已知的调整input信息的重复实验。 当最终的程序准备好进行实际testing时,盐(种子)可以通过要求用户移动鼠标,将鼠标移动与一些击键混合并且从开始时join微秒计数来创build最后的力量。
Windows随机数种子是从鼠标,键盘,networking和时间数字的集合中获得的。 这是不可重复的。 但是,如果如上所述,这个盐值可能被重新设定为已知的种子,则参与实验的devise。
哦,是的,Linux有两个随机数发生器。 一,默认是模32位,另一个是模64位。 您的select取决于准确性需求和您希望用于testing或实际使用的计算时间。