为什么 java.util.Random 使用掩码?
简化(即,排除并发性)Random.next(int bits)
看起来像是
protected int next(int bits) {
seed = (seed * multiplier + addend) & mask;
return (int) (seed >>> (48 - bits));
}
使用掩码将种子减少到 48 位。为什么它比仅仅更好
protected int next(int bits) {
seed = seed * multiplier + addend;
return (int) (seed >>> (64 - bits));
}
?我读过很多关于随机数的文章,但没有发现这样做的原因。
Simplified (i.e., leaving concurrency out) Random.next(int bits)
looks like
protected int next(int bits) {
seed = (seed * multiplier + addend) & mask;
return (int) (seed >>> (48 - bits));
}
where masking gets used to reduce the seed to 48 bits. Why is it better than just
protected int next(int bits) {
seed = seed * multiplier + addend;
return (int) (seed >>> (64 - bits));
}
? I've read quite a lot about random numbers, but see no reason for this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
原因是较低的位往往具有较低的周期(至少对于 Java 使用的算法而言)
来自 Wikipedia -线性同余发生器:
编辑:
进一步阅读后(方便地在维基百科上),a、c 和 m 的值必须满足这些条件才能具有完整的周期:
c 和 m 必须互质
a-1 可被 m 的所有质因数整除
如果 m 是 4 的倍数,则 a-1 是 4 的倍数< /p>
我能清楚地看出唯一仍然满意的是 #3。 #1 和 #2 需要检查,我有一种感觉,其中一个(或两个)都失败了。
The reason is that the lower bits tend to have a lower period (at least with the algorithm Java uses)
From Wikipedia - Linear Congruential Generator:
edit:
after further reading (conveniently, on Wikipedia), the values of a, c, and m must satisfy these conditions to have the full period:
c and m must be relatively primes
a-1 is divisible by all prime factors of m
a-1 is a multiple of 4 if m is a multiple of 4
The only one that I can clearly tell is still satisfied is #3. #1 and #2 need to be checked, and I have a feeling that one (or both) of these fail.
来自 java.util.Random 顶部的文档:
因此整个算法被设计为操作 48 位种子,而不是 64 位种子。我想你可以向 Knuth 先生提出这个问题;p
From the docs at the top of java.util.Random:
So the entire algorithm is designed to operate of 48-bit seeds, not 64 bit ones. I guess you can take it up with Mr. Knuth ;p
来自 wikipedia (@helloworld922 发布的引文所暗示的引文):
此外,它继续(我的斜体):
最后,原因可能是历史性的:Sun 的人们想要可靠地工作的东西,而 Knuth 公式给出了 32 个有效位。请注意
java.util.Random
API 是这么说的(我的斜体):所以我们坚持将其作为参考实现。然而,这并不意味着您不能使用另一个生成器(以及 Random 子类或创建新类):
来自同一维基百科页面:
有一个适合您的 64 位公式。
随机数很棘手(正如 Knuth 指出的那样),根据您的需要,如果您需要 64 位数字,您可能只需调用 java.util.Random 两次并连接这些位就可以了。如果您确实关心统计属性,请使用类似 Mersenne Twister 的东西,或者如果您关心信息泄漏/不可预测性使用
java.security.SecureRandom
。From wikipedia (the quote alluded to by the quote that @helloworld922 posted):
And furthermore, it continues (my italics):
In the end, the reason is probably historical: the folks at Sun wanted something to work reliably, and the Knuth formula gave 32 significant bits. Note that the
java.util.Random
API says this (my italics):So we're stuck with it as a reference implementation. However that doesn't mean you can't use another generator (and subclass Random or create a new class):
from the same Wikipedia page:
There's a 64-bit formula for you.
Random numbers are tricky (as Knuth notes) and depending on your needs, you might be fine with just calling
java.util.Random
twice and concatenating the bits if you need a 64-bit number. If you really care about the statistical properties, use something like Mersenne Twister, or if you care about information leakage / unpredictability usejava.security.SecureRandom
.这样做似乎没有一个充分的理由。
使用掩模是一种保守的方法,使用经过验证的设计。
忽略它很可能会产生更好的生成器,但是,在不了解数学的情况下,这是一个冒险的步骤。
掩码的另一个小优点是 8 位架构上的速度增益,因为它使用 6 个字节而不是 8 个字节。
It doesn't look like there was a good reason for doing this.
Applying the mask is an conservative approach using a proven design.
Leaving it out most probably leads to a better generator, however, without knowing the math well, it's a risky step.
Another small advantage of masking is a speed gain on 8-bit architectures, since it uses 6 bytes instead of 8.