1. ホーム
  2. c++

[解決済み] <random> はLinuxでは同じ数字を生成するが、Windowsでは生成しない。

2023-03-05 03:08:41

質問

以下のコードは、区間 [1,100] にある5つの疑似乱数のリストを生成するためのものである。私は default_random_enginetime(0) で、システム時間を返します。 ユニックス時間 . このプログラムを Windows 7 上で Microsoft Visual Studio 2013 を使ってコンパイルして実行すると、期待通りに動作します (下記参照)。しかし、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;
    
    
  • このエンジンが乱数を生成する方法は、x i+1 = (16807x i + 0) mod 2147483647.

  • したがって、種が1だけ異なる場合、ほとんどの場合、最初に生成される数は16807だけ異なることになります。

  • このジェネレータの範囲は[1, 2147483646]です。libstdc++ の方法である uniform_int_distribution がこれを範囲 [1, 100] の整数にマップする方法は、本質的に次のとおりです。 n . この数が 2147483600 よりも大きくない場合は、以下を返します。 (n - 1) / 21474836 + 1 を返す。そうでなければ、新しい数字で再試行する。

    大半の場合、2つの n が 16807 だけ異なる場合、この手順では [1, 100] で同じ数字が得られることが容易にわかるでしょう。実際、生成された数は約 21474836 / 16807 = 1278 秒または 21.3 分ごとに 1 つ増加すると予想され、これはあなたの観測とよく一致しています。

MSVC の default_random_enginemt19937 であり、この問題はありません。