これはC#よりも数学に関連している可能性がありますが、C#ソリューションが必要なので、ここに配置します。
私の質問は、乱数ジェネレーターの確率についてです。より具体的には、可能な各値が等しい確率で返されるかどうかです。
Random.Next(int、int) メソッドがあり、最初の整数と最後の整数の間の数値を返します(最後の整数は排他的です)。
Random.Next()
[オーバーロードなし]は、0からInt32.MaxValue(2147483647)-1の間の値を返すため、2147483646です。
1〜10の値が必要な場合は、Random.Next(1, 11)
を呼び出してこれを行うことができますが、1〜10のすべての値が発生する確率は同じですか?
たとえば、範囲は10であるため、2147483646は10で完全に割り切れないため、値1〜6の確率はわずかに高くなります(_2147483646 % 10 = 6
_のため)。もちろん、これは、Random.Next()
[オーバーロードなし]内のすべての値が、0から2147483646までの値を等しい確率で返すことを前提としています。
範囲内のすべての数値が同じ確率で発生することをどのように保証しますか?一部の人が他の人よりも高い確率を持っていることが不公平である宝くじタイプのシステムについて考えてみましょう。これにRNGに組み込まれたC#を使用するとは言っていませんが、例として使用していました。
私はあなたの投稿の肉の質問に実際に誰も答えなかったことに注意します:
たとえば、範囲は10であるため、2147483646は10で完全に割り切れないため、値1〜6の確率はわずかに高くなります(2147483646%10 = 6であるため)。もちろん、これは、[オーバーロードなしの] Random.Next()内のすべての値が、等しい確率で0から2147483646までの値を返すことを前提としています。
範囲内のすべての数値が同じ確率で発生することをどのように保証しますか?
そうです、不均衡の原因となる値を捨てるだけです。たとえば、{ 0, 1, 2, 3, 4 }
で一様分布を生成できるRNGがあり、それを使用して{ 0, 1 }
で一様分布を生成したいとします。素朴な実装は次のとおりです。{0, 1, 2, 3, 4}
から描画し、値% 2
を返します。ただし、これにより、明らかに偏ったサンプルが生成されます。これは、ご存知のように、5
(アイテムの数)が2で割り切れないために発生します。したがって、代わりに、値4
を生成するドローをスローします。したがって、アルゴリズムは次のようになります。
draw from { 0, 1, 2, 3, 4 }
if the value is 4, throw it out
otherwise, return the value % 2
この基本的な考え方を使用して、一般的な問題を解決できます。
ただし、1から10までのすべての値が発生する確率は同じですか?
はい、そうです。から [〜#〜] msdn [〜#〜] :
疑似乱数が選択されます有限の数のセットから等しい確率で。
編集:どうやらドキュメントは.NETの現在の実装と一致していません。ドキュメントにはドローが均一であると記載されていますが、コードはそうではないことを示唆しています。しかし、それはこれが解決可能な問題であるという事実を否定するものではなく、私のアプローチはそれを解決する1つの方法です。
RNGに組み込まれているC#は、ご想像のとおり、均一に分散されています。 Next(min, max)
に指定した範囲を指定すると、すべての数値が発生する可能性は等しくなります。
たとえば、1Mのサンプルを取得し、各数値が実際に表示される回数を保存することで、これを自分でテストできます(私が持っています)。グラフ化すると、ほぼ平坦な曲線になります。
また、尤度が等しい各数値各数値が同じ回数発生することを意味するわけではありません。 1から10までの乱数を、100回の反復で見ている場合は番号ごとに10回の出現が均等に分布することはありません。いくつかの数は8回発生する可能性があり、他の数は12または13回発生する可能性があります。ただし、反復回数が増えると、これはある程度均等になる傾向があります。
また、コメントで言及されているので、追加します。より強力なものが必要な場合は、暗号化PRNGを調べてください。 Mersenne Twisterは、私が見たもの(高速、計算コストが安い、膨大な期間)から特に優れており、C#でオープンソースの実装があります。
テストプログラム:
var a = new int[10];
var r = new Random();
for (int i = 0; i < 1000000; i++) a[r.Next(1, 11) - 1]++;
for (int i = 0; i < a.Length; i++) Console.WriteLine("{0,2}{1,10}", i + 1, a[i]);
出力:
1 99924 2 100199 3 100568 4 100406 5 100114 6 99418 7 99759 8 99573 9 100121 10 99918
結論:
各値は等しい確率で返されます。
灰とdtbが正しくない:いくつかの数字が他の数字よりも発生する可能性が高いと疑うのは正しいことです。
.Next(x, y)
を呼び出すと、y --xの可能な戻り値があります。 .NET 4.0 Random
クラスは、NextDouble()
の戻り値に基づいて戻り値を計算します(これは少し簡略化された説明です)。
明らかに、可能なdouble値のセットは有限であり、ご存知のように、.Next(x, y)
の可能な戻り値のセットのサイズの倍数ではない場合があります。したがって、入力値のセットisが均一に分布していると仮定すると、一部の出力値はわずかに高い確率で発生します。
数値のdouble値がいくつあるか(つまり、無限大とNaN値を除く)はわかりませんが、確かに2 ^ 32より大きくなります。あなたの場合、議論のために2 ^ 32の値を想定すると、4294967296の入力を10の出力にマッピングする必要があります。一部の値では、発生する確率が429496730/429496729高くなるか、0.00000023283064397913028110629パーセント高くなります。実際、入力状態の数は2 ^ 32よりもより大きいであるため、確率の差はさらに小さくなります。