2011-11-29 126 views
11

可能重複:
Why does it appear that my random number generator isn't random in C#?
How can I generate truly (not pseudo) random numbers with C#?創建一個真正的隨機

我創建了一個骰子游戲,骰子是基於一個百分點,至100。

public static void Roll() 
{ 
    Random rand = new Random((int)DateTime.Now.Ticks); 
    return rand.Next(1, 100); 
} 

但我不覺得這是一個基於當前時間的真正的隨機數。

如果我做

for (int i = 0; i < 5; i++) 
{ 
    Console.WriteLine("#" + i + " " + Roll()); 
} 

,他們都將是相同的值,因爲DateTime.Now.Ticks沒有改變,它的種子數量相同。

我想我可以生成一個新的隨機種子,如果種子是一樣的,由於當前的時間,但它並不覺得自己是個誠實的「再卷」

我應該怎麼做嘗試並複製一個接近真實/誠實的骰子卷?我應該使用RNGCryptoServiceProvider類來生成卷嗎?

+0

我建議閱讀下面的內容:http://csharpindepth.com/Articles/Chapter12/Random.aspx – Oded

+1

這個問題在SO上有很多變種。這裏有一個...... [爲什麼看起來我的隨機數生成器在C#中不是隨機的?](http://stackoverflow.com/questions/932520/why-does-it-appear-that-my- random-number-generator-isnt-random-in-c)...標記爲僞裝。 (你應該只有一個你的Random的靜態實例,而不是每個Roll的新Random) – spender

+0

什麼是「真正的隨機」? – Sandy

回答

10

DateTime.Now.Ticks僅有的approximately 16ms的分辨率,因此,如果您創建一個Random與超載16ms的「老虎」,他們將全部使用相同的種子值中多次出現,因此你會得到相同的序列。

初始化您Random您的循環外,使得單個Random序列產生時,而不是在環內創建它每次這可能導致Randoms具有相同值的被接種等產生相同的序列。

更新

我以前的一點是,默認的構造函數與CPU蜱初始化Random是不正確的,默認的構造函數實際上使用Environment.TickCount是:含有量

的32位有符號整數自上次計算機啓動以來經過的時間(以毫秒爲單位)。

其中仍然有一個低分辨率。如果快速連續創建多個Random實例,則可以在同一時間段內輕鬆創建它們,因此具有相同的種子值,並創建相同的序列。創建一個Random的實例並使用它。

更新

而且您的意見,如果你想生成多個線程隨機序列,請參閱下面的喬恩斯基特文章,其中討論了一個線程安全的包裝:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

+0

默認的random()種子是當前的CPU ticks嗎? – Kyle

+0

@凱爾我已經更新了我的答案。 –

+0

謝謝。 ^。^我不知道是否應該使用隨機,因爲我使用線程。我讀過隨機不是線程安全的。如果我在函數外部初始化random(),我認爲它會導致問題。 – Kyle

4

你應該在你的Roll函數之外創建你的Random類,並且使用一個唯一值對它進行種子處理。

每當您調用Roll導致'不是隨機數'時,您正在重新創建隨機數。

+0

感謝您鑑別此事。 ^^ – Kyle

0

我假設你正在調用Roll()方法那麼快,Now.Ticks是一樣的嗎?

解決此問題的最簡單方法是,每次調用Roll()時創建一個新的Random()實例,以創建一個靜態變量來保存單個實例Random()

+0

是的,這是問題。感謝您的幫助。 – Kyle

1

我應該使用RNGCryptoServiceProvider類生成卷嗎?

如果這是一個賭注嚴重的遊戲,那麼:是的。

+1

錢不在風險之中。我想複製逼真的卷軸。所以當人們玩時,感覺就像他們在擲骰子一樣。 – Kyle

+0

隨機會綽綽有餘,但請閱讀關於播種的其他答案。 –

+0

我會使用它,因爲random()不是線程安全的。儘管我今天學了一些關於random()的更多內容。 – Kyle

0

使用隨機數生成器的常用方法是將它們播種一次,保存並在整個程序中重複調用它們。只要你在開始時從適當的值開始種子,你應該得到可接受的隨機性 - 假設你正在使用的發生器使用函數返回適合你的目的的隨機數。因此,將您的Random實例保存在Roll()函數外部,在第一次使用時將其種下,然後每次需要另一個數字時調用Next()。

當你正確地理解它時,計算機上就不存在真正的隨機數生成,只有基於種子的僞隨機序列。但是,人類在識別隨機性方面非常糟糕,所以通常都可以。

+0

哈哈@人類識別隨機性。謝謝您的幫助。 ^^ – Kyle

7

僞隨機數生成器像Random只應接種一次,所以:

private static Random _rand = new Random(); 
public static int Roll() 
{ 
    return _rand.Next(1, 100); 
} 

(請注意我做的返回值int,而不是void;在Roll功能引的問題結果在語法錯誤。)

但你的標題說「創建一個真正的隨機」Random不會爲你做,它是一個pseudo-random號碼生成器,這意味着它是確定性的,只是很難預測你是否不知道種子。通常這對於大多數目的來說已經足夠了,但是如果你需要一個隨機性,你需要一個熵源。 http://random.org是一個受歡迎的。

+1

謝謝你提到這一點。我在基於內存的線程中重寫了它,這是一個語法錯誤。感謝您的幫助。 – Kyle