この質問の回答について Recommended way to initialize srand?最初のコメントでは、srand()
はアプリケーション内で1回しか呼び出されないと言われています。それはなぜそうですか?srand() - なぜそれを一度だけ呼び出すのですか?
答えて
これは、達成しようとしている内容によって異なります。
ランダム化は、開始値、すなわちを持つ関数として実行されます。です。
同じシードの場合、常に同じ値のシーケンスが得られます。
ランダムな値が必要なときにシードを設定しようとすると、シードが同じ数になると、常に同じ「ランダム」な値になります。
シードは通常time(NULL)
のように秒で表示されるため、乱数を取る前に常にシードを設定すると、srand/randを呼び出すと同じ番号が返されます複数回コンボする同じ秒に。
この問題を回避するため、アプリケーションインスタンスの2つが同じ秒で実行されるのは疑わしいので、srandは1回だけ設定されるため、各インスタンスは異なる乱数シーケンスを持ちます。
しかし、あなたのアプリケーションを実行する可能性はわずかです(特に、短いものやコマンドラインツールなど)を何回も実行すると、何か他のものに頼らなければなりませんシードを選択する方法(異なるアプリケーションインスタンスで同じシーケンスがあなたによって正常でない限り)。しかし、私が言ったように、それはあなたのアプリケーションの使用状況に依存します。
また、あなたは(同じシードの可能性を最小限に抑える)マイクロ秒の精度を高めるために試してみたいことがあり、(sys/time.h
)が必要です。
struct timeval t1;
gettimeofday(&t1, NULL);
srand(t1.tv_usec * t1.tv_sec);
@Kornelije ...詳しい説明。たくさんありがとう。遅れて申し訳ありません。最後の数日間は外出していました。 –
サイドノート: 'gettimeofday'はPOSIX 2008では時代遅れです。代わりに' clock_gettime'を導入しました。これは '-lrt'でリンクする必要があります。しかし、まだ多くのプラットフォームで利用可能ではないかもしれません。 Linuxではこれは問題ありません。 Macではまだ利用できないと思う。 Windowsではおそらく決して利用できません。 – Shahbaz
t1.tv_usecはlong intで、srandはunsigned intを入力としてとります。 (そして、私はちょうどそれが違いを生む問題に遭遇しました) – Jiminion
なぜなら、srand()
はランダムジェネレータの初期状態を設定しており、ジェネレータが生成するすべての値は自分自身の状態に触れないと「十分にランダム」であるからです。あなたができる例えば
:
int getRandomValue()
{
srand(time(0));
return rand();
}
、その後time()
は、あなただけの同じ値が生成されます隣接の呼び出しで同じ値を返すように、あなたは繰り返しその関数を呼び出す場合 - それはデザインによってです。
srandをシード擬似乱数ジェネレータ。それを複数回呼び出すと、RNGを再出荷します。同じ引数で呼び出すと、同じシーケンスが再開されます。
#include <cstdlib>
#include <cstdio>
int main() {
for(int i = 0; i != 100; ++i) {
srand(0);
printf("%d\n", rand());
}
}
あなたは同じ番号が100回印刷表示されます。あなたのようなシンプルな何かをする場合
は、それを証明するために。質問はCについてであり、C++に関するものではありません。 –
乱数は実際には擬似乱数です。最初にシードが設定され、そこからそれぞれrand
の呼び出しが乱数を取得し、内部状態が変更され、この新しい状態が次のrand
コールで使用されて別の番号を取得します。これらの「乱数」を生成するために特定の式が使用されるため、rand
を呼び出すたびにシードの特定の値を設定すると、コールから同じ番号が返されます。たとえば、srand (1234); rand();
は同じ値を返します。最初の状態をシード値で初期化すると、内部状態をsrand
に設定しないため、十分な乱数が生成され、乱数を生成する可能性が高くなります。
通常、シード値を初期化するときに返される秒の値はtime (NULL)
です。 srand (time (NULL));
がループしているとします。ループは1秒間に複数回反復することができます。したがって、ループ内のループが2回目のループ内で反復処理される回数は、同じ "乱数"を返すので望ましくありません。プログラムの開始時にそれを一度初期化するとシードが1回設定され、rand
が呼び出されるたびに新しい番号が生成され、内部状態が変更されるので、次の呼び出しrand
は十分にランダムな番号を返します。例えば
http://linux.die.net/man/3/randからこのコードは:
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
内部状態next
グローバルとして宣言されています。各myrand
コールは、内部状態を変更して更新し、乱数を返します。 myrand
のすべての呼び出しは異なるnext
の値を持つため、メソッドは呼び出しごとに異なる数値を返します。
mysrand
の実装を見てください。渡すシード値を単にnext
に設定します。したがって、rand
を呼び出す前に毎回同じnext
の値を設定すると、同じランダムな値が返されます。これは、同じ式が適用されているためです。これは、関数がランダムになるため好ましくありません。
しかし、あなたのニーズに応じて、シードをいくつかの値に設定して、各ベンチマークなどで同じ「ランダムシーケンス」を生成することができます。
あなたの答えはこの質問の最も詳細な答えだと言わなければなりません。どのように「ランド」と「サンド」がどれくらい動作するかについて完璧に説明されています。 – manty
mysrand()のパラメータに(unsigned long seed)を使用していませんか? – Jiminion
@Jiminionこれは 'man srand'のコードスニペットです。範囲は0〜32767(RAND_MAXと仮定)で、これは「long」の範囲よりもはるかに小さい値です。内部の乗算と加算が 'unsigned int 'の範囲を超えるので、状態変数' next'は 'long'になります。その後、結果は上記の指定された範囲内でスケーリングまたは変更されます。あなたは種を「長く」作ることができますが。 – phoxis
同じ秒で実行されるアプリケーションインスタンスの異なるシードを生成するためにsrandを使用するより簡単なソリューションが見られます。
srand(time(NULL)-getpid());
この方法では、スレッドがいつ開始されたかを推測する方法がなく、pidも異なるため、シードがランダムに非常に近くなります。
短い答え:srand()
はではなく、乱数ジェネレータの「サイコロを振る」のようなものです。それはカードのデッキをシャッフルするようなものでもありません。何かがあれば、それはカードのデッキを切り取るようなものです。
このように考える。 rand()
は大きなカードのデッキからのもので、あなたがそれを呼び出すたびに、デッキの一番上の次のカードを選んで値を与え、そのカードをデッキの一番下に戻します。 (はい、それは「ランダム」シーケンスは、しばらく後に繰り返されます意味それはしかし、非常に大きなデッキです:。。通常は4,294,967,296カード)さらに
、あなたのプログラムが実行されるたびに、カードのブランドの新しいパックゲームショップから購入された場合、とカードのすべての新しいパックは常に同じシーケンスを持ちます。だから特別なことをしない限り、あなたのプログラムが実行されるたびに、まったく同じ "ランダム"の数字がrand()
から返されます。
ここで、「さて、デッキをシャッフルするにはどうすればいいですか?答えは(少なくともrand
とsrand
が関係している限り)、デッキをシャッフルする方法はありません。
srand
とは何ですか?私がここに構築した類推に基づいて、srand(n)
と呼ぶのは基本的には「デッキn
のカードを上から切る」のようなものです。しかしもう一度待ってください:それは実際に別の真新しいデッキを取って、それをn
カードを上からカットします。
あなたがsrand(n)
、rand()
、srand(n)
、rand()
、...を呼び出す場合毎回同じn
で、あなただけの、非常にランダムでないシーケンスを取得することはできませんので、あなたが実際に戻って同じ番号を取得します毎回rand()
から(未srand
にあなたが利き、必ずしも同じ数が、バック何度もrand
から同じ数。)
だから、あなたができる最善ので、つまり、一度srand()
を呼び出し、一度デッキをカットすることですあなたのプログラムの初めには、n
が適度にランダムであるため、プログラムが実行されるたびに大きなデッキの別のランダムな場所から開始します。
[P.S.はい、私が知っている、現実の生活の中で、カードの新しいデッキを購入するとき、それは通常、順不同ではありません。ここでの類推のために、あなたがゲームショップから購入する各デッキは、一見無作為な順序であると考えていますが、同じ店から購入したカードの他のデッキと全く同じようにランダムな順序です。 (橋のトーナメントで同じようにシャッフルされたカードのように)
1 \ rand()が実行されるたびに、次のrand()の新しいシードが設定されます。 (NULL)が変更されない場合)、次のrand()がrand()と同じになる場合に問題が発生します。以前のsrand()の直後。
主なポイントは、同じシードで 'srand()'を数回初期化すると、 'rand()'が返す値と同じ値になります。 –
- 1. KnockoutJs - なぜinitバインディングハンドラは一度だけ呼び出されますか?
- 2. なぜデストラクタは一度だけ呼び出されましたか?
- 3. イベントのディスパッチャは一度だけ呼び出されますC#
- 4. Loader:onLoadFinishedは一度だけ呼び出されます
- 5. Android:FastScrolling SectionIndexer getSections()は一度だけ呼び出されます
- 6. DependencyProperties:PropertyChangedCallBackは一度だけ呼び出されます
- 7. Androidサービスクラス - OnCreateは一度だけ呼び出されます
- 8. RecyclerView.onBindViewHolderは一度だけ呼び出されます
- 9. Windowsフックは一度だけ呼び出されます
- 10. AuthorizeAttributeは一度だけ呼び出されます
- 11. Android - サービス - 開始コマンドで一度だけ呼び出される
- 12. メソッドはそのライフサイクルで一度だけ呼び出さなければならない
- 13. アンドロイドで一度だけブロードキャストレシーバを呼び出すには?
- 14. @Scheduleメソッドを一度に1回だけ呼び出す方法
- 15. iOS:一度だけメソッドを呼び出す
- 16. ピカソは一度だけトランスフォームを呼び出します
- 17. 関数を一度だけ呼び出す
- 18. Javaスイングコンボボックス一度だけ呼び出すリスナー
- 19. run()は一度呼び出されるのはなぜですか?
- 20. ListView/OnClickにProgressBarを追加すると、一度だけ呼び出される
- 21. Androidカスタムビューは、一度だけ呼び出されるonDrawを取得します。
- 22. 依存プロパティのRaisePropertyChangedは一度だけ呼び出されます
- 23. Androidサービス:onBind(インテント)とonUnbind(インテント)は一度だけ呼び出されます
- 24. なぜこれは一度だけ追加されますか?
- 25. 偽装:一度だけ呼び出すか、呼び出しごとに呼び出しを続けるMVC2 callng - > WCF
- 26. なぜactiveresource.rbはactive_resource.rbを呼び出すだけですか?ここ
- 27. Androidのイベントは、アクティビティが破棄されるまで一度だけ呼び出されますか?
- 28. 角度:$ watchがなぜ呼び出されていますか?
- 29. なぜ私のコードは一度だけnilを出力しますか?
- 30. 一度しか呼び出されない関数をもう一度呼び出すと、どのような引数を投げるべきですか?
ループで、srandを呼び出してからrandを呼び出す –
Dilbertの[Tour of Accounting](http://dilbert.com/strip/2001-10-25)も参照してください。 –