簡體   English   中英

范圍內等概率的隨機數

[英]Random number in range with equal probability

這可能比 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 中的當前實現不一致。 文檔說明抽簽是統一的,但代碼表明它不是。 然而,這並不能否定這是一個可解決的問題的事實,我的方法是解決它的一種方法。

正如您所期望的,RNG 中內置的 C# 是一種均勻分布的。 給定您為Next(min, max)指定的范圍,每個數字都有相等的發生可能性。

你可以自己測試(我有),比如,100 萬個樣本並存儲每個數字實際出現的次數。 如果你繪制它,你會得到一條幾乎平坦的曲線。

另請注意,每個數字具有相同的可能性並不意味着每個數字將出現相同的次數。 如果您正在查看從 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

結論:

每個值都以相等的概率返回。

Ashes 和 dtb 是不正確的:您懷疑某些數字比其他數字更容易出現是正確的。

當您調用.Next(x, y) ,有 y - x 可能的返回值。 .NET 4.0 Random類根據NextDouble()的返回值計算返回值(這是一個稍微簡化的描述)。

顯然,可能的 double 值集是有限的,並且如您所見,它可能不是.Next(x, y)的可能返回值集的大小的倍數。 因此,假設輸入值的集合均勻分布的,一些輸出值出現的概率會稍大一些。

我不知道有多少雙精度數值(即,不包括無窮大和 NaN 值),但它肯定大於 2^32。 在你的情況下,如果我們假設 2^32 個值,為了論證,那么我們必須將 4294967296 個輸入映射到 10 個輸出。 某些值的發生概率會大 429496730 / 429496729,或者大 0.00000023283064397913028110629%。 事實上,由於輸入狀態的數量大於2^32,概率的差異會更小。

我在Microsoft Visual Studio Community 2017版本15.9.6,Microsoft .NET Framework版本4.7.03056中使用C#。 在我直接計算出5.6525%的答案的分析中(由另一位研究人員驗證),我進行了500億輪的模擬,得出5.4721%。 我的仿真需要我生成范圍為[1,i]和[i,38]且i = 1,2,...,38的隨機整數,因此我使用Random.Next(1,i + 1)和Random下一步(i,39) 我花了幾天時間尋找數學上的一些錯誤來解釋差異,從而驗證了仿真模型的各個方面。 最終,我質疑Random.Next()是否在我需要的時間間隔內真正生成了制服。 我換了所有隨機數生成器(例如,請參閱: http : //www.prowaretech.com/Computer/DotNet/Mersenne )並使用Mersenne扭曲器,問題消失了。 只是一個警告性的故事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM