22

byteushortsbyteshortint、およびの範囲で乱数を生成する必要がありuintます。C# の Random メソッドを使用してこれらすべての型を生成できます (例: values.Add((int)(random.Next(int.MinValue + 3, int.MaxValue - 2)));uint を除く) 。これRandom.Nextは、最大 int 値のみを受け入れるためです。

random を生成する簡単な方法はありuintますか?

4

4 に答える 4

28

最も簡単な方法は、おそらく 2 つの呼び出しを使用することです。1 つは 30 ビット用で、もう 1 つは最後の 2 ビット用です。この回答の以前のバージョンでは、包括的な上限が であると想定されてRandom.Next()いましたが、排他的であることが判明したため、30 均一ビットしか取得できません。int.MaxValue

uint thirtyBits = (uint) random.Next(1 << 30);
uint twoBits = (uint) random.Next(1 << 2);
uint fullRange = (thirtyBits << 2) | twoBits;

(もちろん、代わりに 2 つの 16 ビット値を使用することもできます... またはその間のさまざまなオプションを使用できます。)

NextBytesまたは、 を使用して 4 バイト配列を埋めてから、 を使用することもできますBitConverter.ToUInt32

于 2013-06-13T05:59:23.970 に答える
20

ホセのデイライトダイス

または、真のランダム単位を生成する簡単な方法はありますか?

私は認めます、それはOQではありません。真のものではないランダムな uint を生成するより高速な方法があることが明らかになります。それにもかかわらず、何らかの理由で非フラットなディストリビューションが必要な場合を除いて、それらを生成することにあまり興味を持っている人はいないと思います。C# で簡単かつ迅速に行うための調査から始めましょう。私がコードを書くとき、Easy と Fast はしばしば同義語のように振る舞います。

最初: いくつかの重要なプロパティ

MSDNを参照してください。

Randomコンストラクタ:

  • Random()Random:時間依存のデフォルト シード値を使用して、クラスの新しいインスタンスを初期化します。
  • Random(int seed)Random:指定されたシード値を使用して、クラスの新しいインスタンスを初期化します。

パフォーマンスを向上させるには、新しいオブジェクトをRandom繰り返し作成して 1 つの乱数を生成するのではなく、1 つのオブジェクトを作成して時間の経過とともに多くの乱数を生成します。Random

private static Random rand = new Random();

Randomメソッド:

  • rand.Next(): ゼロ以上で 未満の正の乱数を返しますint.MaxValue
  • rand.Next(int max): 0 以上で max 未満の正の乱数を返します。max は 0 以上である必要があります。
  • rand.Next(int min, int max): min 以上で max 未満の正の乱数を返します。max は min 以上である必要があります。

Homework は、rand.Next()が の約 2 倍速いことを示していrand.Next(int max)ます。

2 番目: 解決策。

正の int が 2 ビットしかない場合、符号ビットは忘れてください。ゼロであり、rand.Next()等しい確率で 3 つの異なる値を返します。

00
01
10

真の乱数の場合、最上位ビットと同じように、最下位ビットは 1 と同じ頻度で 0 になります。
最下位ビットで機能させるには、次のようにします。rand.Next(2)

int に 3 ビットがあり、rand.Next()7 つの異なる値を返すとします。

000
001
010
011
100
101
110

最下位 2 ビットで機能させるには、次のようにします。rand.Next(4)

int にnビットがあるとします。nビット
で機能させるには、次を使用します。rand.Next(1 << n)

最大 30 ビットで動作させるには、次を使用します: rand.Next(1 << 30)
It's the maximum, 1 << 31 is large than int.MaxValue.

これは、真のランダム単位を生成する方法につながります。

private static uint rnd32()
{
    return (uint)(rand.Next(1 << 30)) << 2 | (uint)(rand.Next(1 << 2));
}

簡単なチェック: ゼロを生成する可能性は?

1 << 2 = 4 = 2 2 , 1 << 30 = 2 30

ゼロの可能性は次のとおりです: 1/2 2 * 1/2 30 = 1/2 32 ゼロを含む uint の総数: 2 32
日光と同じくらい澄んでいて、スモッグ アラートはありませんね。

最後に:誤解を招く考え。

を使用してより速く行うことは可能ですかrand.Next()

                            int.Maxvalue is:    (2^31)-1
   The largest value rand.Next() returns is:    (2^31)-2 
                           uint.MaxValue is:    (2^32)-1

rand.Next()2 回使用して結果を加算すると、可能な最大値は次のようになります。

2*((2^31)-2) = (2^32)-4 

uint.MaxValue との違いは次のとおりです。

(2^32)-1 - ((2^32)-4) = 3

に到達するにuint.MaxValueは、別の値をrand.Next(4)追加する必要があるため、次のようになります。

rand.Next() + rand.Next() + rand.Next(4)

ゼロを生み出すチャンスは?

おおよそ: 1/2 31 * 1/2 31 * 1/4 = 1/2 64 、それは 1/2 32であるべきです

ちょっと待ってください。

2 * rand.Next() + rand.Next(4)

繰り返しますが、ゼロを生成するチャンスは何ですか?

おおよそ: 1/2 31 * 1/4 = 1/2 33、小さすぎて真にランダムにはなりません。

別の簡単な例:

rand.Next(2) + rand.Next(2)、考えられるすべての結果:

       0 + 0 = 0
       0 + 1 = 1
       1 + 0 = 1
       1 + 1 = 2

等確率?まさかホセ。

結論: 真の乱数を加算すると乱数が得られますが、真の乱数ではありません。公正なサイコロを2つ投げて……

于 2013-08-20T10:05:18.410 に答える
1

System.Random を使用して、「 uint u0 <= 戻り値 <= uint u1 」の範囲を設定します。

「ゼロ」(含む)から「u」(含む)までの範囲から始める方が簡単です。
あなたは私の他の 答えを見てみるかもしれません。 より高速で効率的な方法に興味がある場合:
範囲内の一様擬似乱数。(かなりの量のコード/テキストです)。

"rnd32(uint u)" の下では、0 <= value <= u が返されます。
最も難しいケースは、「u = int.MaxValue」です。次に、「do ループ」の最初の繰り返し
(外側と内側の「do ループ」の両方の単一の繰り返し) が有効な値を返す可能性は 50% です。
2 回繰り返した後の確率は 75% などです。

外側の「do-loop」が複数回繰り返される可能性はわずかです。
「u=int.MaxValue」の場合:0%。

「rnd32(uint u0, uint u1)」が u0 (incl) と u1 (incl) の間の値を返すことは明らかです。

private static Random rand = new Random();

private static uint rnd32(uint u)                                 //  0 <= x <= u
{
    uint x;
    if (u < int.MaxValue) return (uint)rand.Next((int)u + 1);
    do                                         
    {
        do x = (uint)rand.Next(1 << 30) << 2;
        while (x > u);
        x |= (uint)rand.Next(1 << 2);
    }
    while (x > u);
    return x;
}

private static uint rnd32(uint u0, uint u1)                      // set the range
{
    return u0 < u1 ? u0 + rnd32(u1 - u0) : u1 + rnd32(u0 - u1);
}
于 2013-09-08T20:12:45.713 に答える