簡體   English   中英

了解Visual C++的rand() function的算法

[英]Understanding the algorithm of Visual C++'s rand() function

在 C/C++ 中,我們通常會使用rand()srand()來獲取隨機 integer。 但是當我嘗試自己重寫時,發現算法很難理解。 function 很容易只用幾行寫出來,但公式是誤解。

主要公式:

ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L;

涉及的原始代碼:

void __cdecl srand (unsigned int seed)
{
    _getptd()->_holdrand = (unsigned long)seed;
}

int __cdecl rand (void)
{
    _ptiddata ptd = _getptd();
    return ( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff );
}

這只是模運算。 您將乘以並添加到以 2^32 為模的數字(例如),並將高 16 位作為您的“隨機”數字返回。 因為您正在將與模數互質的數字相乘和相加,所以這會創建一種均勻分布的數字。

仔細選擇這兩個數字非常重要。 例如,如果您使用了“* 4”和“+ 8”,您可能不會遇到很多隨機性。

這種方案稱為線性同余

該偽隨機數生成器是一個線性同余生成器

您可以在本月(7-2011)發表於 Dr. Dobb's Journal (DDJ) 的一篇優秀文章中找到對線性同余生成器 (LCG) 和其他類似系列或偽隨機生成器的解釋,以及關於這些特定常數的選擇的說明:快速、高質量、並行隨機數生成器:比較實現

我認為您需要在 DDJ 的網站上注冊(免費)才能閱讀本文的第一部分(鏈接),但是如果您喜歡 C++ 和數學,無論如何您都應該這樣做...

正如已經說過的那樣,它是一個線性同余,(如果您想深入了解這些如何生成偽隨機值,您可以查看它)

種子存儲在_getptd()->_holdrand(以下稱為holdrand)

此代碼通過執行正常的乘法和加法步驟“起作用”,但隨后溢出 holdrand 以獲得隱含的“模數”0x100000000。

我提到這一點是因為它不是很明顯,而且通常不被認為是好的風格。

從技術上講,溢出 integer 變量會引發未定義的行為,但在大多數平台上它是完全可以預測的,因此微軟的工程師忽略了這個問題。

在調用 rand 之前,由於 srand 的手冊頁指出“如果沒有提供種子值,則 rand() function 會自動為種子值 1 提供種子”,因此調用 rand 的更好方法是首先調用 srand,這將“將其參數設置為 rand() 返回的新偽隨機整數序列的種子”。

例如,考慮在 bash shell 腳本中使用的 awk、nawk、gawk 代碼來創建新的(參考)macaddrrandom 腳本。

enter code here
BEGIN {
     n0 = "00"
     srand()
     n1 = sprintf("%02x", int(255 * rand()))
     n2 = sprintf("%02x", int(255 * rand()))
     n3 = sprintf("%02x", int(255 * rand()))
     n4 = sprintf("%02x", int(255 * rand()))
     n5 = sprintf("%02x", int(255 * rand()))
     print n0":"n1":"n2":"n3":"n4":"n5
}

其中 bash shell 腳本中的代碼片段是:

enter code here
ifconfig eth0 down
newmacaddr=`nawk -f .genmacaddr -`
ifconfig eth0 hw ether $newmacaddr
ifconfig eth0 up

如果我沒記錯的話,srand 的種子值來自系統時鍾。

我希望這可以幫助您了解一種可行的編碼解決方案的方法。

暫無
暫無

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

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