<random> 在 Linux 中生成相同的数字,但在 Windows 中不生成
<random> generates same number in Linux, but not in Windows
下面的代码旨在生成区间[1,100]内的五个伪随机数的列表。我用time(0)
作为default_random_engine
的种子,它以unix时间返回系统时间。当我使用Microsoft Visual Studio 2013在Windows 7上编译并运行这个程序时,它的工作效果与预期一样(见下文)。然而,当我在Arch Linux中使用g++编译器这样做时,它的行为很奇怪。
在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上,第一个数字会周期性地加1。在得到上述输出后,我等待了大约30分钟,再次尝试发现第一个数字已经改变,现在总是以26的形式生成。它周期性地增加1,现在是32。这似乎与time(0)
的变化值相对应。
为什么第一个数字很少在运行期间改变,然后当它改变时,增加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;
}
是这样的:
-
default_random_engine
在libstdc++ (GCC的标准库)是minstd_rand0
,这是一个简单的线性同余引擎:typedef linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
-
这个引擎生成随机数的方式是xi+1 = (16807xi + 0) mod 2147483647.
-
因此,如果种子相差1,那么大多数情况下,第一次生成的数将相差16807。
-
此发生器的范围为[1,2147483646]。libstdc++的
uniform_int_distribution
将其映射到[1,100]范围内的整数的方法本质上是这样的:生成一个数字n
。如果数字不大于2147483600,则返回(n - 1) / 21474836 + 1
;否则,用新号码再试一次。很容易看出,在绝大多数情况下,两个相差仅16807的
n
在此过程中会产生相同的数字[1,100]。事实上,人们会期望生成的数字大约每21474836/16807 = 1278秒或21.3分钟增加一个,这与你的观察结果非常吻合。
MSVC的default_random_engine
是mt19937
,没有这个问题
std::default_random_engine
是实现定义的。请使用std::mt19937
或std::mt19937_64
。
另外std::time
和ctime
函数不是很精确,使用<chrono>
头文件中定义的类型代替:
#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方法的优势在于,在设计使用群体信息的某些实验时,可以测量已知的输入信息调整实验的重复。当最终程序准备好进行实际测试时,盐(种子)可以通过要求用户移动鼠标来创建,将鼠标移动与一些按键混合在一起,并添加从最后一次通电开始的微秒计数。
Windows随机数种子是从收集鼠标、键盘、网络和一天中的时间数字中获得的。这是不可复制的。但是,如果如上所述,参与实验设计的人可以将该盐值重置为已知种子。
哦,是的,Linux有两个随机数生成器。一个,默认是模32位,另一个是模64位。您的选择取决于准确性需求和您希望在测试或实际使用中消耗的计算时间。
- 代码在main()中运行,但在函数中出现错误
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 换位表导致测试失败(但在游戏中运行良好)
- 库标题在标题中不可见,但在 cmake build 下.cpp文件中完全可见.为什么?
- 树莓上的 Libtorch 无法加载 pt 文件,但在 ubuntu 上工作
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- 编译在我的 Mac 上工作,但在集群 (Linux) 上不起作用
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- 我的代码运行良好,但在游戏循环中中断
- C++ assigment std::list:<typename>:itrator 在 main 中工作,但在方法中它不起作用
- C++代码在台式机上工作正常,但在笔记本电脑上则不行
- 实现 DFS 在较短的输入下工作正常,但在较大的输入下会抛出分段错误
- 为什么数组在一个文件中打印,但在发送到另一个文件时却缺少数字
- 我正在尝试编写一个函数来计算C++数字的数字根,但在编译后出现错误
- 逗号分隔的数字在模拟器上正确显示,但在iPad上没有显示
- 在C++中,从只知道起始数字(但需要整行)的文本文件中检索某一行
- <random> 在 Linux 中生成相同的数字,但在 Windows 中不生成