web-dev-qa-db-ja.com

<random>はLinuxでは同じ数を生成しますが、Windowsでは生成しません

以下のコードは、間隔[1,100]で5つの擬似乱数のリストを生成することを意図しています。 _default_random_engine_にtime(0)をシードします。これは、システム時間を nix time で返します。 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分待ってから、1番目の数値が変更され、現在は常に26として生成されていることを再度確認しようとしました。 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;
}
_
88
Amin Mesbah

ここで何が起こっているのですか:

  • default_random_engine libstdc ++(GCCの標準ライブラリ)のminstd_Rand0は、単純な線形合同エンジンです。

    typedef linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_Rand0;
    
  • このエンジンが乱数を生成する方法はxですi + 1 =(16807x + 0)mod 2147483647。

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

  • このジェネレーターの範囲は[1、2147483646]です。 libstdc ++のuniform_int_distributionを[1、100]の範囲の整数にマップする方法は、本質的にこれです:数値を生成しますn。数値が2147483600を超えない場合、(n - 1) / 21474836 + 1を返します。そうでない場合は、新しい番号で再試行してください。

    ほとんどの場合、この手順では、16807だけ異なる2つのnが[1、100]の同じ数を生成することを簡単に確認できます。実際、生成された数は、21474836/16807 = 1278秒または21.3分ごとに1つずつ増加することが予想されます。これは、観測とかなり一致しています。

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

139
T.C.

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;
}
28
Casey