我在讨论this来自C标准的rand()
非常简单的实现:
static unsigned long int next = 1;
int rand(void) /* RAND_MAX assumed to be 32767. */
{
next = next * 1103515245 + 12345;
return (unsigned)(next/65536) % 32768;
}
从this Wikipedia article我们知道乘数a
(在上面的代码a = 1103515245
中)应该只满足2个条件:
a - 1
可被m
的所有素数因子整除
(在我们的例子中m = 2^32
,int的大小,所以m
只有一个素因子= 2)a - 1
是4的倍数,则m
是4的倍数
(32768是4的倍数,也是1103515244)为什么他们选择了这么奇怪,难以记住,“男人,我厌倦了这些随机数字,写下任何”数字,如1103515245?
也许有一些明智的理由,这个数字比另一个更好?
例如,为什么不设置a = 20000000001
?它更大,更酷,更容易记住。
答案 0 :(得分:35)
如果你使用LCG在d维空间上绘制点,它们将最多位于(d!m) 1 / d hyperplanes。这是LCG的一个已知缺陷。
如果你没有仔细选择a和m(超出完全周期的条件),它们可能位于比那更少的平面上。这些数字是通过所谓的光谱测试选择的。
“光谱测试”(名称来自数论)是d维关节分布所在的连续超平面之间的最大距离。你希望它尽可能小,因为你可以测试它们。
有关该主题的历史回顾,请参阅this paper。请注意,您引用的生成器在文章中提到(作为ANSIC)并且确定不是很好。然而,高阶16位是可接受的,但是许多应用程序将需要超过32768个不同的值(正如您在评论中指出的那样,周期确实是2 ^ 31--维基百科链接中完整周期性的条件可能只是必要的)。
ANSI文档中的原始源代码没有采用高阶16位,产生一个非常差的生成器,很容易被误用(rand() % n
是人们首先想到的在{{1之间绘制一个数字}和0
,这会产生一些非随机的东西(在这种情况下)。
另见数值配方中关于LCG的讨论。引用:
更糟糕的是,许多早期的发电机特别糟糕 m和a的选择。一个臭名昭着的例行程序,RANDU,a = 65539 和m = 231,在IBM大型计算机上广泛存在多年, 并广泛复制到其他系统上。我们其中一人回忆起毕业生 学生制作一个只有11架飞机的“随机”情节并被告知 由他的计算机中心的编程顾问,他滥用 随机数生成器:“我们保证每个数字是随机的 个别地,但我们不保证不止一个 随便。“这使我们的研究生教育至少停止了一年!
答案 1 :(得分:6)
请记住,rand()
是uniform distribution的近似值。使用这些数字是因为它们经过测试表明它们可以产生更加统一的分布。
鉴于可表示范围内的大量无符号整数对,我怀疑是否有人用所有有效种子尝试了所有这些整数。如果您认为您有更好的参数选择,那就试一试吧!你有代码,只需要考虑LCG的参数并运行测试。生成一堆数字(比如1000万),计算生成数字的直方图并绘制出来以查看分布。
修改强> 如果您有兴趣开发用于实际应用的伪随机数发生器,我建议您阅读有关该主题的大量文献。上面给出的“建议”仅建议帮助表明选择任意“更大,更酷,更容易记住”的LCG参数将导致非常差的分布。 的 /修改
此外,它是一个库函数,我从未见过使用标准库版rand()
来记住其LCG参数的程序。
答案 2 :(得分:2)
早期计算倾向于关注位和字节,并使用寄存器来减少代码字节(在行有字节之前)
我在下面只找到了一条合理的线索:
此生成器的输出不是很随机。如果我们使用上面列出的样本生成器,那么16个关键字节的序列将是高度非随机的。例如,事实证明rand()的每个连续输出的低位将交替(例如,0,1,0,1,0,1,...)。你明白为什么吗? x * 1103515245的低位与x的低位相同,然后添加12345只是翻转低位。因此低位交替。这将可能键的集合缩小到仅2113种可能性;远低于期望值2128。
http://inst.eecs.berkeley.edu/~cs161/fa08/Notes/random.pdf
两个合理的答案:
改进可怜的随机数发生器(1976) by Bays,Durham Bays,Carter,S D Durham
答案 3 :(得分:0)
这个数字似乎很特别,它只是在两个素数之间:P。
现在认真谈论,看看它是不是一个好选择,只需看看输出。即使翻转一个位,您也会看到非常不同的结果。
另外,考虑一下你期望的可预测性......实施是可怕的,你可以考虑一个更强大而简单的替代方案,如FNV-1a。