C++中生成隨機數的問題?
最近在寫一個平台需要生成隨機數,有下面幾個疑惑
1. 為什麼需要更換種子,一個程序至始至終只設置一次種子,然後一直使用這個種子不行嗎?2. 如果需要更換種子,多久換一次呢,比如每生成1000個數換一次?3. 一般網上有人使用srand((unsigned int)time(NULL))來設置時間的種子,但是如果設置種子的間隔在1s內,那就等於沒有更換種子,這個時候怎麼辦
4. 如果種子不變,rand()生成的隨機數,那麼這個數列是周期的嗎?5. 有沒有寫的比較好的隨機數生成的代碼啊,比如均勻分布,高斯分布
C和C++標準庫的隨機數都是偽隨機數演算法,而且一般來說隨機度不夠也不均勻。
最好採用平台上對應的加密級別的隨機數演算法,隨機度高且均勻,下面給個跨平台的例子:
int GetRandom() {
int rnum = 0;
#if defined _MSC_VER
#if defined _WIN32_WCE
CeGenRandom(sizeof(int), (PBYTE)rnum);
#else
HCRYPTPROV hProvider = 0;
const DWORD dwLength = sizeof(int);
BYTE pbBuffer[dwLength] = {};
DWORD result =::CryptAcquireContext(hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
assert(result);
result = ::CryptGenRandom(hProvider, dwLength, pbBuffer);
rnum = *(int*)pbBuffer;
assert(result);
::CryptReleaseContext(hProvider, 0);
#endif
#elif defined __GNUC__
int fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
(void) read(fd, (void *) rnum, sizeof(int));
(void) close(fd);
}
#endif
return rnum;
}
我這個例子可以在Windows桌面、WinCE和LInux平台運行,輸出是整型隨機數,但是稍加修改可以生成任意長度的隨機數。
首先,對於需要更換種子的理論我不能予以認同,隨機數種子一旦設定,不應再修改。因為只要換種子的方式不正確,往往會破壞隨機數發生器的均勻性和其他性質。假如我們決定換種子,那麼種子是定值還是根據時間日期決定?如果我們選擇定值,那麼產生的隨機序列的周期就可能會大大縮短(假設沒1000次更換一次種子,那麼周期就變成了1000),顯然會大大降低隨機性。而如果我們採用時間來作為隨機數種子,沒1000次更換,如果一秒鐘內有超過1000次獲取隨機數,那麼肯定在這一秒內出現了重複的序列。雖然在上面的論證中,我都假設每產生1000個隨機數換一次種子,事實上用任何的方式決定何時更換隨機數種子,都會影響到產生的序列的隨機質量。除非能給出數學上的證明,某種更換種子的方式保持了隨機序列的均勻性,而且至少不縮減周期性。因此,對於1,2,3問,無需做答。對於4和5:我簡單介紹下隨機序列的產生,和幾個常用的隨機數產生演算法
由於計算機每一步計算的結果都應當是確定無誤的,因此如果計算機不收集外部環境的信息,只能產生偽隨機序列。但是收集外部信息的代價比較高,而是用正確的隨即數產生演算法完全可以滿足需求。
常用的快速隨機數產生演算法是線性同餘演算法和梅森旋轉演算法。平均分布的偽隨機演算法都是周期性的,在一個周期內各個數字的分布概率相等線性同餘很簡單: a[n+1] = (p*a[n] + q) mod m只要正確選擇p和m,可以使得序列的周期為m,Windows和Linux的C運行庫都採用線性同餘演算法,Window C運行庫的隨機序列周期是65536,Linux的C運行庫是2^31,在一個周期內一個數字只出現一次。而設置隨機數種子就相當於設置當前的a[n],下一個隨機數從這裡開始計算產生。但是線性同餘的周期太短了,後來出現了梅森旋轉演算法:演算法的實現和原理請參考wiki,梅森旋轉演算法各項指標非常優秀,現在一般使用的是產生器有2^19937-1長的周期,而且在1-623維均勻分布的(映射到一維直線均勻分布,二維平面內均勻分布,三維空間內均勻分布...)。前面的演算法還不適合用於加密,因為攻擊者如果手機了足夠長的一段序列,就可以從數學上猜解出整個序列。可以用於加密的隨機數生成演算法有RSA隨機數生成演算法等。
而產生高斯分布的隨機數產生演算法,據我所知有box-mueller演算法。沒有詳細展開的請自行wiki。歡迎瀏覽本人博客,前兩天剛寫了關於隨機數的一篇文章,裡面還有facebook 如何生成隨機種子的方法。文章傳送門。
注意:
不知道是csdn啥bug,手機端進入會報404錯誤,大家從pc端點擊進入吧。
誰說的要換種子,打他屁股。
推薦閱讀:
※*a.b()是什麼意思,運算符順序是怎麼看的?
※CS、360、這些軟體的根目錄下有很多不同類型的文件。在沒有VS、JDK這些「程序設計語言」的「支持?
※能不能用c#和c/c++以及其他語言寫一個完整的IDE(類似visual studio)?
※圖中的最長路徑問題怎麼算?
※為什麼X86的寄存器數量沒有隨著性能的提升而增加?