web-dev-qa-db-ja.com

Rand()で常に同じ乱数列を取得するのはなぜですか?

Cで乱数を試すのは初めてです(C#が恋しいです)。ここに私のコードがあります:

_int i, j = 0;
for(i = 0; i <= 10; i++) {
    j = Rand();
    printf("j = %d\n", j);
}
_

このコードを使用すると、コードを実行するたびに同じシーケンスが取得されます。ただし、forループの前にsrand(/*somevalue/*)を追加すると、異なるランダムシーケンスが生成されます。誰でもその理由を説明できますか?

50
Hannoun Yassir

あなたはそれを播種する必要があります。時間をかけて播種することをお勧めします。

srand()

_#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  srand ( time(NULL) );
  printf ("Random Number: %d\n", Rand() %100);
  return 0;
}
_

Rand()を呼び出さないと、srand()の値が1に自動的にシードされるため、同じシーケンスが得られます。

編集

コメントのおかげで

Rand()は、0から_Rand_MAX_(標準ライブラリで定義)の間の数値を返します。 modulo 演算子(_%_)を使用すると、除算の残りRand() / 100が得られます。これにより、乱数は0〜99の範囲内になります。たとえば、0〜999の範囲の乱数を取得するには、Rand() % 1000を適用します。

84
kjfletch

Rand()は pseudo-random 数値を返します。特定のアルゴリズムに基づいて数値を生成します。そのアルゴリズムの開始点は常に同じなので、呼び出しごとに同じシーケンスが生成されます。これは、プログラムの動作と一貫性を検証する必要がある場合に便利です。

srand関数でランダムジェネレーターの「シード」を設定できます(プログラムでsrandを1回だけ呼び出す)Rand()ジェネレーターから異なるシーケンスを取得する一般的な方法の1つは、シードを現在の時間またはプロセスのIDに設定するには:

srand(time(NULL));またはsrand(getpid());プログラムの開始時。

実際のランダム性を生成することはコンピューターにとって非常に困難ですが、実用的な非暗号関連の作業では、生成されたシーケンスを均等に分配しようとするアルゴリズムはうまく機能します。

33
nos

man Rand から引用するには:

Srand()関数は、Rand()によって返される擬似乱数整数の新しいシーケンスのシードとして引数を設定します。これらのシーケンスは、同じシード値でsrand()を呼び出すことで繰り返し可能です。

シード値が提供されない場合、Rand()関数は値1で自動的にシードされます

そのため、シード値がない場合、Rand()はシードを1(あなたの場合は毎回)と想定し、同じシード値を持つRand()は同じ数列を生成します。

19
Aditya Sehgal

ここにはたくさんの答えがありますが、誰もreallyが説明していないようです-または、シードが実際に実行していることです。だからここに行きます。

Rand()関数は内部状態を維持します。概念的には、これをRand_stateと呼ばれる何らかのタイプのグローバル変数と考えることができます。 Rand()を呼び出すたびに、2つのことを行います。既存の状態を使用して新しい状態を計算し、新しい状態を使用して返される数値を計算します。

state_t Rand_state = INITIAL_STATE;

state_t calculate_next_state(state_t s);
int calculate_return_value(state_t s);

int Rand(void)
{
    Rand_state = calculate_next_state(Rand_state);
    return calculate_return_value(Rand_state);
}

これで、Rand()を呼び出すたびに、Rand_stateが所定のパスに沿って1ステップ移動することがわかります。表示されるランダムな値は、そのパスに沿った場所に基づいているため、事前に決められたシーケンスに従います。

Srand()の出番です。パス上の別のポイントにジャンプできます。

state_t generate_random_state(unsigned int seed);

void srand(unsigned int seed)
{
    Rand_state = generate_random_state(seed);
}

State_t、calculate_next_state()、calculate_return_value()、およびgenerate_random_state()の正確な詳細は、プラットフォームによって異なりますが、通常は非常に単純です。

このことから、プログラムを開始するたびに、Rand_stateはINITIAL_STATE(generate_random_state(1)と同等)で開始することがわかります。これが、srand()を使用しない場合、常に同じシーケンスを取得する理由です。

11
caf

乱数生成の章の冒頭でクヌースの独創的な作品「コンピュータープログラミングの技術」からの引用を覚えているとしたら、次のようになります。

「数学的な手段で乱数を生成しようとする人は、技術的に言えば罪の状態にあります」。

簡単に言えば、ストック乱数ジェネレーターはアルゴリズムであり、数学的であり、100%予測可能です。これは、「ランダムな」数字の繰り返し可能なシーケンスが望ましい多くの状況で実際に良いことです-例えば、特定の統計演習では、真にランダムなデータがもたらす結果に「ぐらつき」を望まない場合クラスタリング効果。

コンピューターのハードウェアから「ランダム」データのビットを取得することは人気のある2番目の選択肢ですが、動作環境が複雑になるほど、ランダム性の可能性が高くなりますが、少なくともランダムではありません。

真にランダムなデータジェネレーターは、外部ソースに目を向ける傾向があります。放射性崩壊はクエーサーの挙動と同様にお気に入りです。その根が量子効果にあるものは、事実上ランダムです-アインシュタインの迷惑に大きくなります。

9
Tim H

乱数ジェネレーターは実際にはランダムではなく、ほとんどのソフトウェアが完全に予測可能であることを好みます。 Randが行うことは、ランダムに見えるOneと呼ばれるたびに異なる疑似乱数を作成することです。適切に使用するには、別の開始点を指定する必要があります。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  /* initialize random seed: */
  srand ( time(NULL) );

  printf("random number %d\n",Rand());
  printf("random number %d\n",Rand());
  printf("random number %d\n",Rand());
  printf("random number %d\n",Rand());

  return 0;
}
7
Howard May

これは http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#Rand からのものです:

宣言:

void srand(unsigned int seed); 

この関数は、関数Randが使用する乱数ジェネレーターにシードします。 srandに同じシードをシードすると、Randは擬似乱数の同じシーケンスを返します。 srandが呼び出されない場合、Randはsrand(1)が呼び出されたかのように動作します。

2
Key

Rand()は、シリーズ内の次の(擬似)乱数を返します。何が起こっているのか、その実行のたびに同じシリーズがあります(デフォルトは「1」)。新しいシリーズをシードするには、Rand()の呼び出しを開始する前にsrand()を呼び出す必要があります。

毎回ランダムなものが必要な場合は、次のことを試してください。

srand (time (0));
2
Chet

誰も彼の質問に答えていません。

このコードでは、コードごとに同じシーケンスを取得しますが、forループの前にsrand(/ somevalue /)を追加すると、ランダムシーケンスが生成されます。誰かが理由を説明できますか?

私の教授が私に言ったことから、コードが正しく実行されていることを確認し、何か問題があるかどうか、または何かを変更できるかどうかを確認する場合に使用されます。

0
James

srand(sameSeed)を呼び出す前にRand()を呼び出します。詳細 こちら

0
dfa

Rand()のシード

void srand (unsigned int seed)

この関数は、シードを新しい一連の疑似乱数のシードとして確立します。 srandでシードが確立される前にRandを呼び出すと、デフォルトのシードとして値1が使用されます。

プログラムを実行するたびに異なる擬似乱数系列を生成するには、srand(time(0))を実行します

0
nik