web-dev-qa-db-ja.com

Rand()が実行ごとに同じ数字のシーケンスを生成するのはなぜですか?

Rand()を指定してプログラムを実行するたびに、同じ結果が得られます。

例:

#include <iostream>
#include <cstdlib>

using namespace std;

int random (int low, int high) {
    if (low > high) return high;
    return low + (Rand() % (high - low + 1));
}
int main (int argc, char* argv []) {
    for (int i = 0; i < 5; i++) cout << random (2, 5) << endl;
}

出力:

3
5
4
2
3

プログラムを実行するたびに、毎回同じ数値が出力されます。これを回避する方法はありますか?

33
Patrick Lorio

乱数ジェネレーターのシードは設定されていません。

srand(time(NULL))を呼び出すと、よりランダムな結果が得られます。

_#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    srand(time(NULL));
    cout << Rand() << endl;
    return 0;
}
_

理由は、Rand()関数から生成される乱数は実際にはランダムではないためです。それは単に変換です。ウィキペディアは、疑似乱数ジェネレーターの意味についてのより良い説明を提供しています:決定論的ランダムビットジェネレーターRand()を呼び出すたびに、シードおよび/または生成された最後の乱数を取得します(C標準では使用されるアルゴリズムを指定しませんが、C++ 11には一般的なアルゴリズムを指定する機能があります)、それらの数値に対して数学演算を実行し、結果を返します。したがって、シード状態が毎回同じである場合(真の乱数でsrandを呼び出さない場合のように)、常に同じ「乱数」が出力されます。

詳細を知りたい場合は、次を読むことができます。

http://www.dreamincode.net/forums/topic/24225-random-number-generation-102/

http://www.dreamincode.net/forums/topic/29294-making-pseudo-random-number-generators-more-random/

52
Robert Mason

最初にRand()を呼び出さずにsrand()を呼び出すと、srand(1)を暗黙的に呼び出したように動作します。標準のC99 7.20.2.2 The srand function(それに基づいたcstdlibの関連ビット)の状態:

Srandへの呼び出しが行われる前にRandが呼び出された場合、srandがシード値1で最初に呼び出されたときと同じシーケンスが生成されます。

つまり、will毎回同じシーケンスを取得します。 mainを次のように変更できます。

int main (int argc, char* argv []) {
    srand (time (0));  // needs ctime header.
    for (int i = 0; i < 5; i++)
        cout << random (2, 5) << endl;
    wait ();
}

これを修正するには、1秒に1回以上実行しないと仮定します。

前述のように、これにはctimeヘッダーが必要です。 cstdlibRandが存在する場所であるため、srandもプルする必要があります。また、通常、XXX.hヘッダーではなくcXXXヘッダーを使用することをお勧めします(たとえば、math.hではなくcmath)。

したがって、allそれらの変更(および明示的な名前空間を使用しますが、他の人はそうではないかもしれませんが)で、私は次のようになります:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>

void wait () {
    int e;
    std::cin >> e;
}

int random (int low, int high) {
    if (low > high) return high;
    return low + (std::Rand() % (high - low + 1));
}

int main (int argc, char* argv []) {
    std::srand (std::time (0));
    for (int i = 0; i < 5; i++)
        std::cout << random (2, 5) << '\n';
    wait ();
}

とにかく数回、それを実行するたびに異なるシーケンスを与えます。明らかに、データが繰り返されるタイミングには厳しい制限があります(4つしかない5 そして、出力の「ランダム」な性質は、それ以前にも繰り返される可能性があることを意味します:-)

16
paxdiablo

これはRand()関数の機能です。

持っているのは乱数ジェネレータではなく、より厳密には "Pseudo Random Number Generator" です。同じシード(srand(x)関数を使用してシードする)に対して同じランダムシーケンスを再現できることは、バグを再現したり、プログラムの実行中に状態を保持したりするために重要です。

個人的には、この機能を使用して、 monte carlo ベースのテレインレンダラーでレンダリングプロセスを一時停止/永続化できます。素敵な副作用は、異なるマシンで異なるモンテカルロ実験を保証できることです。したがって、最終ステップでより高い品質の最終結果に減らすことができる保証された異なる結果を生成することができます(もちろん後で再利用できます)この高品質の最終結果により、さらに高品質の結果が得られます。

ただし、CもC++もRand()の番号シーケンスを定義しないことに注意してください。したがって、プラットフォーム間で保証されたシーケンスが必要な場合は、C++ 11の新しい乱数ジェネレーター(たとえば mersenne twister )のいずれかを使用し、独自のロールを使用します(ただし、ほとんどのジェネレーターはほとんど簡単に把握できません。それらのうち、特定のオーバーフロー動作に依存している実装は簡単ではないかもしれません)、またはサードパーティのコンポーネントを使用しています(例:boost :: random)。

3
Sebastian Mach

乱数ジェネレーターをシードする必要があります(関数 'srand'を参照)。暗号化を行っていない場合、「時間」の出力をシードするだけで十分でしょう。

1
Michael Kohne

実際に擬似乱数を取得しています。それらを「よりランダム」にするには、「変化する」もの(最も一般的には現在の時間)を使用して乱数ジェネレーターをシードします。

0
John3136

randomize()を使用します。値を自動的にシードします。または、Rand()を使用する場合は、srand(seedvalue)を使用してシードできます。シード値はシステム時間のようなものにすることができます。それは毎回異なる乱数を与えます

0
Smatik