2012-02-27 13 views
22

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

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

あなたがsrand関数を呼び出した場合(時間(NULL))、その後、あなたが得るより多くのランダムな結果:

理由は、ランド()関数から生成された乱数が実際にランダムではないということです。それは単に変換です。ウィキペディアは、擬似乱数生成器の意味についてのより良い説明を提供します。 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/

1

乱数ジェネレータをシードする必要があります(関数 'srand'を参照)。あなたが暗号をやっていないと仮定すると、 'time'の出力でそれを播種すれば、おそらく十分です。

11

srand()を最初に呼び出すことなくrand()に電話すると、srand(1)が暗黙的に呼び出されたかのように動作します。標準C99 7.20.2.2 The srand functionの関連ビット(cstdlibが基づいている)状態:

srand関数への呼び出しが行われた前のランドが同じ配列がsrand関数は、最初のシードと呼ばれたときのように生成されなければならない、呼び出された場合

つまり、になるたびに同じシーケンスが得られます。あなたが二回以上、それを実行しないと仮定すると、この問題を解決するために

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(); 
} 

:あなたはあなたの中にmainを変更することができます。

前述のとおり、ctimeヘッダーが必要です。 randsrandが住んでいるので、cstdlibにも引き込む必要があります。また、XXX.hヘッダー(math.hではなくcmathなど)ではなく、cXXXヘッダーを使用することをお勧めします。 (他の人がいないかもしれないが、私が好む、明示的な名前空間を使用して)、私は終わるだろう

ので、すべてそれらの変更をした:異なるシーケンスを毎回与え

#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(); 
} 

Iとにかくそれを数回実行してください。明らかに、データがいつ繰り返されるかについての厳しい制限があります(実際にはの可能性があります)。出力の「ランダム」性質は、それ以前にも繰り返される可能性があります:-)

0

実際には疑似乱数それらを「ランダム」にするには、乱数ジェネレータを「変更」するもの(最も一般的には現在の時間)を使用してシードすることができます。

+1

Nit:数学的には、「よりランダム」にはなりません。 –

+0

trueですが、OPの質問の文脈で...(プラス引用符で囲まれています;-) – John3136

2

rand()機能の機能です。

乱数生成器ではありませんが、より厳密には"Pseudo Random Number Generator"です。同一のシード(同じsrand(x)関数を使用してシード)に対して同じランダムシーケンスを再現できることは、バグを再現したり、プログラム実行中の状態を保持する上で重要です。

個人的には、monte carloベースのテレインレンダラーでレンダリングプロセスを一時停止/維持できるようにするために、この機能を使用します。優れた副作用は、異なるマシンで異なるモンテカルロ実験を保証することができ、保証された異なる結果を生成することができ、最終ステップで高品質の最終結果に減らすことができることです。このより高い品質の結果がより高い品質の結果を生み出す)。

ただし、CもC++も数字列をrand()から定義していません。したがって、プラットフォーム間で保証されたシーケンスが必要な場合は、C++ 11の新しい乱数ジェネレータ(たとえばmersenne twister)を使用して独自のロールを作成してください(ほとんどのジェネレータはほとんど把握できません。実装は自明ではないかもしれません)、または第三者のコンポーネント(boost :: randomなど)を使用してください。

1

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

+1

'randomize'は標準のC++関数ではありません。どのプラットフォームについて話していますか? –

関連する問題