2010-04-14 258 views
6

我想爲一個psudo隨機數生成器生成一個好的隨機種子。我想我會得到專家的意見。讓我知道這是否是一種不好的做法,或者是否有更好的方法。C++爲psudo隨機數生成器生成一個很好的隨機種子

#include <iostream> 
#include <cstdlib> 
#include <fstream> 
#include <ctime> 

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/random", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = int(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    return random_seed; 
} // end good_seed() 
+0

別忘了擲骰子和異或與它;) – Andrey 2010-04-14 20:20:10

+2

如果你的過程運行的文件句柄,並無法打開'的/ dev/random'會發生什麼? – 2010-04-14 20:21:16

回答

0

定義好。 :-)

很重要快速找到種子,或種子儘可能隨機不管需要多長時間放在一起?

對於平衡 - 絕對不是最隨意,絕對不是最快的......

  • 當它第一次調用,佔用系統時間,以毫秒爲單位。
  • 通過散列函數(如SHA-1)運行該函數。
  • 使用結果作爲種子。

這應該給你一個大部分隨機的160位,這是變化的10^50左右。散列運行需要一秒鐘的時間,所以這不是閃電般的,但在過去對我來說是一個很好的平衡。

+0

我想爲我的應用程序儘可能隨機,但我也會對快速解決方案感興趣。 – posop 2010-04-14 20:22:07

+3

@DeanJ哈希是多餘的。直接播種系統時間。你試圖用哈希完成的是(好的)僞隨機數發生器已經*做了*(更好)。 – 2010-04-14 20:34:26

+0

Jon-Eric 100%正確;另一方面,我習慣於使用不好的隨機數生成器,不能從壞的隨機數生成器中分辨出好的,並且傾向於堅持(快速)矯枉過正。 – 2010-04-14 20:43:49

1

傳統上,我們已經使用了第一或第二用戶輸入種子我們的值作爲(抽動到毫秒範圍)量所需的時間他們響應是相當變量。

5

從/ dev/random讀取的代碼看起來是錯誤的:你的C風格將你的字符緩衝區的地址轉換爲random_seed_a(這裏用於C++轉換的插件)並忽略你從/ dev/random嘗試*reinterpret_cast<int*>(memblock)

/dev/random應該已經是一個很好的熵源了,所以如果它可用,不可能將該值與任何其他數據一起使用,直接用它作爲種子,如果沒有足夠的數據在的/ dev /隨機我只是回落的時間和使用本身,而不是什麼異或運算它。

+1

根據我的研究,非確定性隨機變量「dev/urandom」與非隨機變量時間(0)相比較仍然是非確定性隨機變量。 – posop 2010-04-14 23:13:52

2

良好的僞隨機數生成器並不需要一個「好」的種子,任何種子(這不同於跑步跑步)效果同樣好。

直接使用系統時間很好(並且很常見)。使用/dev/random也很好。

如果你的僞隨機數發生器不好,即使選擇一個「好」種子也無濟於事。如果可以,請替換它。

建議:Mersenne twister是一個相當不錯重視。即使在最有限的系統上也能運行的前驅物。

+3

根據目的,僞隨機數發生器可能需要一個不可預測的種子。有一個在線撲克遊戲把時間花費在可能是體面的PRNG上,這意味着通過觀察一些卡片,可以找出PRNG開始的位置,從而瞭解整個套牌。 – 2010-04-14 21:07:05

+1

如果用戶無法預測隨機數字序列對用戶來說非常重要,那麼您需要密碼安全的生成器,而不是僞隨機生成器。 (如果你使用僞隨機發生器進行真錢賭博,你會很瘋狂。) – 2010-04-14 21:15:51

+0

僅僅在FYI和Mersenne twister中,你必須觀察624張連續牌(12副牌),然後才能知道所有將來的牌。 – 2010-04-14 21:30:59

0

也許你應該更喜歡/dev/urandom/超過/dev/random。如果沒有足夠的可用熵,後者會在Linux上阻塞,如果程序在沒有用戶交互的機器上運行,很容易發生。如果您無法打開/dev/urandom,則可以拋出異常而不是使用回退。

1

「好」的發電機,「壞發電機」並不意味着什麼。 「任何考慮產生隨機數字的算術方法的人當然都處於犯罪狀態。」 - 約翰馮諾依曼。每個這樣的生成器都只是一個確定性算法。它的重要的是具有足夠的熵的初始狀態(種子)。 根據你的需要,你應該測試你的發電機質量。蒙特卡羅方法是僞隨機數發生器的一個非常好的估計器。

2

好的,這是我在考慮你的輸入後所做的改變。感謝您的一切順便!

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/urandom", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = *reinterpret_cast<int*>(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    std::cout << "random_seed_a = " << random_seed_a << std::endl; 
    std::cout << "random_seed_b = " << random_seed_b << std::endl; 
    std::cout << " random_seed = " << random_seed << std::endl; 
    return random_seed; 
} // end good_seed()