web-dev-qa-db-ja.com

C ++ Rand()が同じ桁数の数値しか生成しないように見えるのはなぜですか?

C/C++で書かれた小さなアプリケーションで、Rand関数とシードの問題に直面しています:

順序が異なる、つまり異なる対数値(基数2)を持つ一連の乱数を生成したいと思います。ただし、生成される数値はすべて同じ順序であり、2 ^ 25から2 ^ 30の間で変動しているようです。

それはRand()がUnix時間でシードされているためでしょうか。私は何を忘れていますか? Rand()の先頭でmain()を1回だけシードしています。

146

1から2までの数字はわずか3%です30 2の間にない25 および230。だから、これはかなり普通に聞こえます:)

なぜなら225 / 230 = 2-5 = 1/32 = 0.03125 = 3.125%

478
C4stor

明るい緑は0〜2の領域です25;濃い緑色は2の間の領域です25 および230。ティックは2の累乗です。

distribution

272
Casey Chu

もっと正確にする必要があります。異なる2を底とする対数値が必要ですが、これにはdistributionが必要ですか?標準のRand()関数は均一な分布を生成します。目的の分布に関連付けられているquantile関数を使用してこの出力を変換する必要があります。

分布を教えてくれれば、必要なquantile関数を教えてくれます。

42
Bathsheba

異なる桁数が必要な場合は、単にpow(2, Rand())を試してみませんか?または、Haroldが提案したように、Rand()として順序を直接選択することもできますか?

18
aspiring_sarge

基本的な(そして正しい)答えはすでに与えられており、上記で受け入れられています: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サンプル):

enter image description here

13
Floris

@ C4storが大きなポイントになりました。しかし、より一般的な場合と人間(10を基数)の理解を容易にするため:1から10 ^ nの範囲では、数値の〜90%が10 ^(n-1)から10 ^ nであるため、数値の〜99%は10 ^(n-2)から10 ^ nになります。必要な数だけ小数を追加してください。

面白い数学、nに対してこれを繰り返していくと、1から10 ^ nまで、 99.9999 ...%= 100% の数字が10 ^ 0から10 ^ nであることがわかります。この方法。

コードについては、0から10 ^ nまでのランダムな桁数の乱数が必要な場合、次のようにします。

  1. 0からnまでの小さな乱数を生成します

  2. Nの範囲がわかっている場合、次数10 ^ kの大きな乱数を生成します(k> max {n})。

  3. 長い乱数をカットして、この大きな乱数のn桁を取得します。

13

0と2 ^ 29および2 ^ 29と2 ^ 30の間に正確に等しい数の数があります。

問題を見る別の方法:生成する乱数のバイナリ表現、最上位ビットが1である確率が1/2に等しいことを考慮してください。したがって、半分の場合に次数29が得られます。必要なのは2 ^ 25未満の数値を表示することですが、これは上位5ビットがすべてゼロであり、1/32の低い確率で発生することを意味します。長い間実行しても、15未満の順序はまったく表示されない可能性があります(確率は6から6回連続してローリングするようなものです)。

さて、種についてのあなたの質問の一部。いいえ、シードは数値の生成元の範囲を決定できない可能性があり、最初の初期要素を決定するだけです。 Rand()は、範囲内のすべての可能な数のシーケンス(所定の順列)と考えてください。シードは、シーケンスから番号の描画を開始する場所を決定します。これが、(疑似)ランダム性が必要な場合、現在の時間を使用してシーケンスを初期化する理由です:開始位置が均一に分散されているかどうかは気にしません。重要なのは、同じ位置から開始しないことだけです。

5
Vadim

pow(2,Rand())を使用すると、希望する大きさの順に答えが返されます!!

2
Shivendra

Wgetを使用できるオンラインサービスから乱数を使用する場合は、乱数生成にrandom.orgなどのサービスも使用できることを確認できます。wgetを使用してそれらをキャッチし、ダウンロードしたファイル

wget -q https://www.random.org/integers/?num=100&min=1&max=100&col=5&base=10&format=html&rnd=new -O new.txt

http://programmingconsole.blogspot.in/2013/11/a-better-and-different-way-to-generate.html

2
Namit Sinha