[英]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.