2011-03-10 137 views
17

考慮這個方法:爲什麼Random.Next()總是返回相同數量的

private static int GenerateRandomNumber(int seed, int max) 
{ 
    return new Random(seed).Next(max); 
} 

在我的機器,執行這個循環通過1500次迭代產生相同數量:

for (int i = 0; i < 1501; i++) 
      { 
       int random = GenerateRandomNumber(100000000, 999999999); 
       Console.WriteLine(random.ToString()); 
       Console.ReadKey(); 
      } 

我得到145156561,每一次迭代。

我沒有緊迫的問題,我只是好奇這種行爲,因爲.Next(max)說:「返回一個非負數隨機數字小於指定的最大值也許我不理解的東西基本。

+7

這正是'seed'的意思。 – SLaks 2011-03-10 19:01:46

+1

我現在明白了。我只是認爲它至少通過智能感知呈現的方式並不那麼明顯。 – kd7 2011-03-10 19:03:51

回答

37

你總是播種一個新的實例使用相同的種子,然後抓住了第一個最大。通過使用種子,你就保證了相同的結果。

如果你想有一個靜態的,隨機的但是,由於Random不是線程安全的,所以在靜態使用時需要一些同步。 ike:

private static Random random; 
private static object syncObj = new object(); 
private static void InitRandomNumber(int seed) 
{ 
    random = new Random(seed); 
} 
private static int GenerateRandomNumber(int max) 
{ 
    lock(syncObj) 
    { 
     if (random == null) 
      random = new Random(); // Or exception... 
     return random.Next(max); 
    } 
} 
+1

如果你需要很多隨機數,這可能會殺死PC :-)如果你在C#4.0下,或者使Random對象線程靜態,至少要使用SpinLock。 – xanatos 2011-03-10 19:06:32

+0

您應該使用雙重檢查鎖定。 – SLaks 2011-03-10 19:08:44

+1

@SLaks:沒有什麼幫助 - Random.Next()不是線程安全的,所以你總是需要一個鎖。這裏的鎖並不適用於懶惰實例...... – 2011-03-10 19:10:04

6

問題是您每次都創建一個具有相同種子編號的新Random實例。您應該創建一個單獨的Random實例(如果需要,將其存儲在靜態中),並簡單地調用該實例上的下一個方法。

隨機數字的生成不是真正的隨機數,更多詳細信息請參閱this Wikipedia entry

3

僞隨機數發生器通常通過選擇一個種子,然後根據該種子生成一個確定性序列。每次選擇相同的種子,您會生成相同的序列。

.NET中只有「2^32個不同的隨機序列。

2

不知道內部工作是如何工作的..檢查wiki,但它非常簡單。

public class MathCalculations 
{ 
    private Random rnd = new Random(); 

    public Int32 getRandom(Int32 iMin, Int32 iMax) 
    { 
     return rnd.Next(iMin, iMax); 
    } 
} 

public class Main 
{ 
    MathCalculations mathCalculations = new MathCalculations(); 
    for (int i = 0; i < 6; i++) 
    { 
     getRandom(0,1000); 
    } 
} 

會產生數字1,數字,3號,號碼4,5號,Number6(1種,許多數字1個序列,隨機*不是真的,但約。*)

不過,若你這樣做:

public class MathCalculations 
{ 
    public Int32 getRandom(Int32 iMin, Int32 iMax) 
    { 
     Random rnd = new Random(); 
     return rnd.Next(iMin, iMax); 
    } 
} 

public class Main 
{ 
    MathCalculations mathCalculations = new MathCalculations(); 
    for (int i = 0; i < 6; i++) 
    { 
     getRandom(0,1000); 
    } 
} 

現在,您將獲得數字1,數字1,數字1,數字1,數字1,數字1(1種,多的數字6組相同的序列,總是選擇從每個等於序列相同的起始編號)..在某些時候,數字1將是不同的,因爲種子會隨着時間的推移而變化......但是你需要等待一些時間我爲此,儘管如此,你從來沒有從序列中挑選數字2。

原因是,每次您使用相同的種子生成一個新的序列時,因此該序列一遍又一遍地重複,每次您的隨機生成將會選擇序列中的第一個數字,同樣的種子,當然總是一樣的。

不知道這是否由技術上的隨機發生器的基礎方法是正確的,但這就是它的行爲。

7

迪爾伯特也遇到了同樣的問題早在2001年:

http://dilbert.com/strips/comic/2001-10-25/

巧合嗎?

我不這麼認爲。

而且random.org同意:http://www.random.org/analysis/

+4

在這裏沒有幽默的空間,真的嗎? – dbrin 2014-01-30 16:29:39

+0

雖然這個鏈接可能回答這個問題,但最好在這裏包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 - [來自評論](/ review/low-quality-posts/18480928) – jv42 2018-01-10 20:01:37

+0

儘管尊重@ jv42,但我不能再現漫畫內容,所以在這種情況下,鏈接是合理的。 – dbrin 2018-01-10 23:33:21

0

倘若有人正在尋找一個「快速和骯髒」,「解決方案」(我謹慎使用這個詞),那麼這將足以滿足大多數。

int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds); 
Random rand = new Random(secondsSinceMidnight); 
var usuallyRandomId = rand.Next(); 

請注意我的使用通常是隨機的。我同意標記爲答案的項目是更正確的方式。

1

薩拉姆全部, 好吧,它也讓我瘋了。答案很簡單。在生成隨機數之前更改種子。

實施例: 我要生成1之間的隨機數到10

Random rnd = new Random(DateTime.Now.Seconds); 
int random_number = rnd.Next(10); 

放入一個循環內,並且運行它的三倍。它會發出10以下的隨機數。