java.util.Random 有多好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/453479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How good is java.util.Random?
提问by Dove
Two Questions:
两个问题:
Will I get different sequences of numbers for every seed I put into it?
对于我放入的每个种子,我会得到不同的数字序列吗?
Are there some "dead" seeds? (Ones that produce zeros or repeat very quickly.)
是否有一些“死”的种子?(产生零或很快重复的那些。)
By the way, which, if any, other PRNGs should I use?
顺便说一句,我应该使用哪些(如果有)其他 PRNG?
Solution: Since, I'm going to be using the PRNG to make a game, I don't need it to be cryptographically secure. I'm going with the Mersenne Twister, both for it's speed and huge period.
解决方案:由于我将使用 PRNG 制作游戏,因此我不需要它具有加密安全性。我会选择 Mersenne Twister,因为它的速度和巨大的周期。
采纳答案by Neil Coffey
To some extent, random number generators are horses for courses. The Random class implements an LCG with reasonably chosen parameters. But it still exhibits the following features:
在某种程度上,随机数生成器是课程的马匹。Random 类使用合理选择的参数实现 LCG。但它仍然表现出以下特点:
- fairly short period (2^48)
- bits are not equally random (see my article on randomness of bit positions)
- will only generate a small fraction of combinationsof values (the famous problem of "falling in the planes")
If these things don't matter to you, then Random has the redeeming feature of being provided as part of the JDK. It's good enough for things like casual games (but not ones where money is involved). There are no weak seeds as such.
如果这些事情对您来说并不重要,那么 Random 具有作为 JDK 的一部分提供的赎回功能。对于休闲游戏之类的东西(但不是涉及金钱的游戏)来说,这已经足够了。没有弱种子。
Another alternative which is the XORShift generator, which can be implemented in Java as follows:
另一种选择是XORShift 生成器,它可以在 Java 中实现如下:
public long randomLong() {
x ^= (x << 21);
x ^= (x >>> 35);
x ^= (x << 4);
return x;
}
For some very cheap operations, this has a period of 2^64-1 (zero is not permitted), and is simple enough to be inlined when you're generating values repeatedly. Various shift values are possible: see George Marsaglia's paper on XORShift Generators for more details. You can consider bits in the numbers generated as being equally random. One main weakness is that occasionally it will get into a "rut" where not many bits are set in the number, and then it takes a few generations to get out of this rut.
对于一些非常便宜的操作,它的周期为 2^64-1(不允许为零),并且非常简单,可以在您重复生成值时进行内联。各种移位值都是可能的:有关更多详细信息,请参阅 George Marsaglia 关于 XORShift Generators 的论文。您可以将生成的数字中的位视为同样随机。一个主要的弱点是,它偶尔会陷入一种“套路”,即数字中没有设置多少位,然后需要几代人才能摆脱这种套路。
Other possibilities are:
其他可能性是:
- combine different generators (e.g. feed the output from an XORShift generator into an LCG, then add the result to the output of an XORShift generator with different parameters): this generally allows the weaknesses of the different methods to be "smoothed out", and can give a longer period if the periods of the combined generators are carefully chosen
- add a "lag" (to give a longer period): essentially, where a generator would normally transform the last number generated, store a "history buffer" and transform, say, the (n-1023)th.
- 组合不同的生成器(例如,将 XORShift 生成器的输出馈入 LCG,然后将结果添加到具有不同参数的 XORShift 生成器的输出中):这通常可以“平滑”不同方法的弱点,并且可以如果仔细选择组合发电机的周期,则给出更长的周期
- 添加“滞后”(以提供更长的时间段):本质上,生成器通常会转换生成的最后一个数字,存储“历史缓冲区”并转换,例如,第(n-1023)个。
I would say avoid generators that use a stupid amount of memory to give you a period longer than you really need (some have a period greater than the number of atoms in the universe-- you really don't usually need that). And note that "long period" doesn't necessarily mean "high quality generator" (though 2^48 is still a little bit low!).
我会说避免使用愚蠢的内存量来给你一个比你真正需要的时间更长的周期(有些周期大于宇宙中的原子数量——你通常不需要那个)。请注意,“长时间”并不一定意味着“高质量生成器”(尽管 2^48 仍然有点低!)。
回答by zvrba
This is described in the documentation. Linear congruential generators are theoretically well-understood and a lot of material on them is available in literature and on the internet. Linear congruential generator with same parameters always outputs the same periodic sequence, and the only thing that seed decides is where the sequence begins. So the answer to your first question is "yes, if you generate enough random numbers."
这在文档中有所描述。线性同余生成器在理论上很容易理解,并且在文献和互联网上可以找到很多关于它们的材料。具有相同参数的线性同余生成器总是输出相同的周期序列,并且种子唯一决定的是序列从哪里开始。所以你的第一个问题的答案是“是的,如果你生成足够多的随机数。”
回答by Jon Skeet
As zvrba said, that JavaDoc explains the normal implementation. The Wikipedia page on pseudo-random number generatorshas a fair amount of information and mentions the Mersenne twister, which is not deemed cryptographically secure, but is very fast and has various implementations in Java. (The last link has two implementations - there are others available, I believe.)
正如 zvrba 所说,JavaDoc 解释了正常的实现。关于伪随机数生成器的维基百科页面有相当多的信息,并提到了Mersenne twiner,它不被认为在密码学上是安全的,但速度非常快,并且在 Java 中有各种实现。(最后一个链接有两个实现 - 我相信还有其他实现。)
If you need cryptographically secure generation, read the Wikipedia page - there are various options available.
如果您需要加密安全生成,请阅读维基百科页面 - 有多种可用选项。
回答by Michael Borgwardt
As RNGs go, Sun's implementation is definitely not state-of-theart, but's good enough for most purposes. If you need random numbers for cryptography purposes, there's java.security.SecureRandom, if you just want something faster and better than java.util.random, it's easy to find Java implementations of the Mersenne Twister on the net.
随着 RNG 的发展,Sun 的实现绝对不是最先进的,但对于大多数用途来说已经足够了。如果您需要用于加密目的的随机数,可以使用java.security.SecureRandom,如果您只是想要比 java.util.random 更快更好的东西,很容易在网上找到 Mersenne Twister 的 Java 实现。
回答by John D. Cook
If RNG quality really matters to you, I'd recommend using your own RNG. Maybe java.util.Random is just great, in this version, on your operating system, etc. It probably is. But that could change. It's happened before that a library writer made things worse in a later version.
如果 RNG 质量对您来说真的很重要,我建议您使用您自己的 RNG。也许 java.util.Random 很棒,在这个版本中,在你的操作系统上,等等。它可能是。但这可能会改变。之前发生过一个库作者在以后的版本中使事情变得更糟的情况。
It's very simple to write your own, and then you know exactly what's going on. It won't change on upgrade, etc. Here's a generatoryou could port to Java in 10 minutes. And if you start writing in some new language a week from now, you can port it again.
编写自己的代码非常简单,然后您就确切地知道发生了什么。它不会在升级等时改变。这是一个可以在 10 分钟内移植到 Java的生成器。如果你一周后开始用某种新语言写作,你可以再次移植它。
If you don't implement your own, you can grab code for a well-known RNG from a reputable source and use it in your projects. Then nobody will change your generator out from under you.
如果您不实现自己的,您可以从信誉良好的来源获取知名 RNG 的代码并在您的项目中使用它。那么没有人会从你下面更换你的发电机。
(I'm not advocating that people come up with their own algorithms, only their own implementation. Most people, myself included, have no business developing their own algorithm. It's easy to write a bad generator that you think is wonderful. That's why people need to ask questions like this one, wondering how good the library generator is. The algorithm in the generator I referenced has been through the ringer of much peer review.)
(我不是提倡人们想出自己的算法,而只是他们自己的实现。大多数人,包括我自己,都没有能力开发自己的算法。很容易编写一个你认为很棒的糟糕的生成器。这就是为什么人们需要问这样的问题,想知道库生成器有多好。我引用的生成器中的算法已经通过了许多同行评审。)
回答by Dimitris Andreou
See the answer in my blog post:
请参阅我的博客文章中的答案:
http://code-o-matic.blogspot.com/2010/12/how-long-is-period-of-random-numbers.html
http://code-o-matic.blogspot.com/2010/12/how-long-is-period-of-random-numbers.html
Random has a maximal period for its state (a long, i.e. 2^64 period). This can be directly generalized to 2^k - invest as many state bits as you want, and you get the maximal period. 2Mersenne Twister has actually a very shortperiod, comparatively (see the comments in said blog post).
Random 的状态有一个最大周期(很长,即 2^64 周期)。这可以直接推广到 2^k - 根据需要投资尽可能多的状态位,并获得最大周期。2Mersenne倍捻机实际上有一个很短的时期,相对(见说,博客文章的评论)。
--Oops. Random restricts itself to 48bits, instead of using the full 64 bits of a long, so correspondingly, its period is 2^48 after all, not 2^64.
——哎呀。Random 将自己限制在 48 位,而不是使用 long 的完整 64 位,因此相应地,它的周期毕竟是 2^48,而不是 2^64。