web-dev-qa-db-ja.com

ランダムなuintを生成する

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

ランダムなuintを生成する簡単な方法はありますか?

17
jaqui

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

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 を使用することもできます。

23
Jon Skeet

ホセのデイライトダイス

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

確かに、それはOQではありません。真のuintではないランダムなuintを生成するより速い方法があることが明らかになります。それにもかかわらず、何らかの理由で非一様分布が必要な場合を除いて、誰もそれらを生成することにあまり興味がないと思います。 C#で簡単かつ高速に実行するために、いくつかのresearchから始めましょう。コードを書くとき、簡単で速いことはしばしば同義語のように振る舞います。

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

[〜#〜] 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):ゼロ以上、最大未満の正の乱数を返します。最大はゼロ以上である必要があります。
  • Rand.Next(int min, int max):min以上、max未満の正の乱数を返します。maxはmin以上である必要があります。

宿題は、Rand.Next()Rand.Next(int max)の約2倍の速さであることを示しています。

2番目:解決策。

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

_00
01
10
_

真の乱数の場合、最下位ビットは1であるのと同じくらい頻繁にゼロであり、最上位ビットでも同じです。
最下位ビットで機能させるには、次を使用します: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)
最大値です。1<< 31は_int.MaxValue_よりも大きくなります。

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

_private static uint rnd32()
{
    return (uint)(Rand.Next(1 << 30)) << 2 | (uint)(Rand.Next(1 << 2));
}
_

簡単なチェック:ゼロを生成するチャンスは何ですか?

1 << 2 = 4 = 22、1 << 30 = 230

ゼロの可能性は次のとおりです:1/22 * 1/230 = 1/232 ゼロを含むuintの総数:232
日光のようにはっきりしていて、スモッグの警告はありませんね。

最後に:誤解を招くアイデア。

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/231 * 1/231 * 1/4 = 1/264、1/2にする必要があります32

ちょっと待ってください、どうですか:

_2 * Rand.Next() + Rand.Next(4)
_

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

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

別の簡単な例:

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

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

等しい確率?まさかホセ。

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

17
P_P

System.Randomを使用して、範囲 "uint u0 <=戻り値<= uintu1"を設定します。

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

以下の「rnd32(uintu)」は次を返します:0 <=値<= u。
最も難しいケースは、「u = int.MaxValue」です。次に、「do-loops」の最初の反復が
(外側と内側の両方の「do-loop」の単一の反復)は、50%の有効な値を返します。
2回の反復後、確率は75%などになります。

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

「rnd32(uintu0、uint u1)」がu0(含む)とu1(含む)の間の値を返すことは明らかです。

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);
}
0
P_P