C/C++ で書かれた小さなアプリケーションで、rand
関数とおそらくシードの問題に直面しています。
次数が異なる、つまり異なる対数値 (底 2) を持つ一連の乱数を生成したいと考えています。しかし、生成された数値はすべて同じ順序で、2^25 と 2^30 の間で変動しているようです。
rand()
それは、今では比較的大きな数である Unix time がシードされているためですか? 私は何を忘れていますか?rand()
の冒頭で一度だけシードしていmain()
ます。
1 から 2 30の間にあり、2 25から 2 30の間にない数はわずか 3% です。だから、これはかなり正常に聞こえます:)
2 25 / 2 30 = 2 -5 = 1/32 = 0.03125 = 3.125% なので
明るい緑色は 0 ~ 2 25の領域です。濃い緑色は 2 25と 2 30の間の領域です。ティックは 2 の累乗です。
異なる桁数が必要な場合は、単に試してみpow(2, rand())
ませんか? それとも、ハロルドが提案したように、rand() として直接順序を選択するのでしょうか?
基本的な (そして正しい) 答えは既に与えられ、上で受け入れられています: 0 から 9 の間に 10 個の数字、10 から 99 の間に 90 個の数字、100 から 999 の間に 900 個などがあります。
ほぼ対数分布の分布を計算上効率的に取得するには、乱数を乱数で右シフトします。
s = rand() & 31; // a random number between 0 and 31 inclusive, assuming RAND_MAX = 2^32-1
r = rand() >> s; // right shift
完璧ではありませんが、コンピューティングよりもはるかに高速ですpow(2, rand()*scalefactor)
。これは、分布が係数 2 内の数値に対して均一であるという意味で「塊状」になります (128 から 255 では均一、256 から 1023 では密度の半分など)。
以下は、0 から 31 までの数値の頻度のヒストグラムです (1M サンプル)。
0 と 2^29 の間と 2^29 と 2^30 の間には、正確に同じ数の数があります。
問題の別の見方: 生成する乱数の 2 進数表現を考えてみましょう。最上位ビットが 1 である確率は 1/2 に等しいため、半分のケースで次数 29 になります。必要なのは 2^25 未満の数値を表示することですが、これは上位 5 ビットがすべてゼロであることを意味し、1/32 という低い確率で発生します。長時間実行しても、15 未満の順序はまったく表示されない可能性があります (確率は、6 6 回連続してローリングするようなものです)。
さて、種に関する質問の一部です。いいえ、シードは数値が生成される範囲を決定することはできません。最初の初期要素を決定するだけです。rand() は、範囲内のすべての可能な数値のシーケンス (事前に決定された順列) と考えてください。シードは、シーケンスから数字の描画を開始する場所を決定します。これが、(疑似)ランダム性が必要な場合、現在の時間を使用してシーケンスを初期化する理由です。開始位置が均一に分散されていなくてもかまいません。重要なのは、同じ位置から開始しないことだけです。