1. ホーム
  2. c++

srandの推奨初期化方法について教えてください。

2023-11-10 10:38:57

質問

C++で擬似乱数生成器を初期化するための「良い」方法が必要です。私が見つけたのは 記事 には、次のように書かれています。

乱数のようなものを生成するために を生成するために、srandは通常、初期化されます。 を、実行時間に関連するような特徴的な値に初期化します。 実行時間に関連した値です。例えば によって返される値は 関数time (ヘッダ ctimeで宣言されている)が返す値は,毎秒異なり,これは これは,ほとんどの ランダムの必要性には十分な特徴です。

Unixtimeは私のアプリケーションにとって十分に特徴的ではありません。これを初期化するためのより良い方法は何でしょうか?移植可能であればボーナスポイントがありますが、コードは主にLinuxホスト上で実行されるでしょう。

私は、intを得るためにいくつかのpid/unixtimeの計算を行うか、あるいはおそらく /dev/urandom .

ありがとうございます!

EDIT

はい、実際に1秒間に何度もアプリケーションを起動しており、衝突に遭遇しています。

どのように解決すればよいのでしょうか。

ベストアンサーは <random> . C++11以前のバージョンを使用している場合は、Boost乱数のものを見ることもできます。

しかし、もし私たちが rand()srand()

は <ストライク ベスト 最も簡単な方法は、単に time() :

int main()
{
    srand(time(nullptr));

    ...
}

を呼び出すたびにではなく、必ずプログラムの冒頭で行うようにしてください。 rand() !


サイドノート

ノート : 以下のコメントで、これが安全でないことについての議論があります(これは真実ですが、最終的には関係ありません(続きを読む))。そこで代替案として、ランダムデバイスからシードする方法があります。 /dev/random (または他の安全な本物の乱数生成器) を使うことです。 しかし : この言葉に騙されてはいけません。これは rand() を使っているのです。たとえ見事に生成されたシードを使ったとしても、それは予測可能です(任意の値を持っていれば、次の値の完全なシーケンスを予測することができます)。これは生成する際にのみ有効で "pseudo" ランダムな値を生成する場合にのみ有効です。

もしあなたが安全であることを望むなら、あなたはおそらく <random> (を使うべきでしょう(ただし、私はセキュリティに詳しいサイトでもう少し読みます)。出発点として、以下の回答を参照してください。 https://stackoverflow.com/a/29190957/14065 をご覧ください。

二次的な注記: ランダムなデバイスを使用することは、実際には、以下の私のオリジナルの提案よりも、1 秒間に複数のコピーを開始する問題を解決します (セキュリティの問題だけではありません)。


元のストーリーに戻る。

起動するたびに、time() は一意な値を返します (アプリケーションを 1 秒間に何度も起動しない限り)。32ビットシステムでは、60年ごとくらいにしか繰り返されません。

あなたは時間が十分にユニークでないと思っているようですが、私はそれを信じるのは難しいと思っています。しかし、私は間違っていることが知られています。

もしあなたがアプリケーションの多くのコピーを同時に開始するのであれば、より細かい解像度のタイマーを使用することができます。しかし、その場合、値が繰り返されるまでの期間が短くなる危険性があります。

OK、では、本当に1秒間に複数のアプリケーションを起動していると考えるなら。

それなら、タイマーの粒を細かくして使ってください。

 int main()
 {
     struct timeval time; 
     gettimeofday(&time,NULL);

     // microsecond has 1 000 000
     // Assuming you did not need quite that accuracy
     // Also do not assume the system clock has that accuracy.
     srand((time.tv_sec * 1000) + (time.tv_usec / 1000));

     // The trouble here is that the seed will repeat every
     // 24 days or so.

     // If you use 100 (rather than 1000) the seed repeats every 248 days.

     // Do not make the MISTAKE of using just the tv_usec
     // This will mean your seed repeats every second.
 }