c ++ - <random>在Linux中生成相同的编号,但在Windows中不生成

下面的代码用于生成区间[1,100]中的五个伪随机数的列表。 我用time(0)播种time(0),它以unix时间返回系统时间。 当我使用Microsoft Visual Studio 2013在Windows 7上编译和运行此程序时,它按预期工作(见下文)。 但是,当我使用g ++编译器在Arch Linux中这样做时,它表现得很奇怪。

在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;
}
Amin Mesbah asked 2019-09-10T12:03:19Z
3个解决方案
138 votes

这是发生了什么:

  • libstdc ++(GCC的标准库)中的default_random_enginemt19937,这是一个简单的线性同余引擎:

    default_random_engine
  • 该引擎生成随机数的方式是xi + 1 =(16807xi + 0)mod 2147483647。

  • 因此,如果种子相差1,那么大多数时候第一个生成的数字将相差16807。

  • 该发生器的范围是[1,2147483646]。 libstdc ++的default_random_engine将它映射到[1,100]范围内的整数的方式基本上是这样的:生成数字mt19937。如果数字不大于2147483600,则返回(n - 1) / 21474836 + 1; 否则,请尝试使用新号码。

    应该很容易看出,在绝大多数情况下,两个仅相差16807的default_random_engine将在此过程中在[1,100]中产生相同的数字。 实际上,人们会期望生成的数字每21474836/16807 = 1278秒或21.3分钟增加一,这与您的观察结果非常吻合。

MSVC的default_random_enginemt19937,它没有这个问题。

T.C. answered 2019-09-10T12:04:22Z
28 votes

std::time是实现定义的。 请改用ctime<chrono>

另外std::timectime函数不是很准确,请使用<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;
}
Casey answered 2019-09-10T12:04:55Z
-2 votes

在Linux中,随机函数在概率意义上不是随机函数,而是伪随机数生成器。它用种子腌制,并且基于该种子,产生的数字是伪随机且均匀分布的。Linux方法的优点在于,在使用来自群体的信息的某些实验的设计中,可以测量具有已知的输入信息调整的实验的重复。 当最终程序准备好进行实际测试时,盐(种子)可以通过要求用户移动鼠标,将鼠标移动与一些键击混合并添加一些微秒计数来创建。 最后的电源。

Windows随机数种子是从鼠标,键盘,网络和时间数字的集合中获得的。 这是不可重复的。 但是如果如上所述,可以将该盐值重置为已知种子,其中一个参与实验设计。

哦,是的,Linux有两个随机数生成器。 一,默认模数为32位,另一种模数为64位。 您的选择取决于您希望在测试或实际使用中消耗的准确度需求和计算时间。

Leslie Satenstein answered 2019-09-10T12:05:36Z
translate from https://stackoverflow.com:/questions/32730906/random-generates-same-number-in-linux-but-not-in-windows