繁体   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