关于android:Java中的Random经常生成相同的值

Random in Java often generating same value

enter image description here

我用这个来生成513之间的值。

1
 int randomGeneratedLevelValue = ThreadLocalRandom.current().nextInt(5, 13);

如何减少相同的匹配?


在一个真正的随机数序列中,没有办法减少重复次数而不偏倚随机数序列。

例如,在你的顺序中,10, 5, 12, 12, 13, 13后面跟另一个12的概率是1比9,也就是说,与范围内任何其他数字的概率相同。

现在,由于您使用的是RandomThreadLocalRandom,您可能看到了线性同余生成器固有的自相关效应。如果是这样,可以使用SecureRandom来消除这些影响。但是,SecureRandom电话的价格要贵得多。

另一种方法是故意偏向重复;例如(伪代码)

1
2
3
4
5
int random = rand.nextInt(...)
if (random == lastRandom) {
     random = rand.nextInt(...);
}
return random;

但要小心。引入偏见可能会产生意想不到的/意想不到的后果。


生日悖论预测随机数的重复概率比你想象的要高得多。例如,它预测,只有23个随机的人,其中两个生日相同的可能性超过50%。根据鸽子洞原理,需要367人才能有100%的复制机会,但复制的概率在这之前是非常高的。

这是概率分布(来自维基百科):enter image description here

在重复概率达到sqrt(2m * p(n))之前必须生成的数字的近似经验法则,其中m是可能的随机数,p(n)是您要查找的概率。因此,例如,如果您在50个数字范围内生成随机数(例如,如果您从100-150中选择一个随机数),那么您只需要生成大约sqrt((2 * 50) * 0.5) = 7.07个随机数,然后概率就可以和没有重复的概率一样好。如果您在50个数字范围内生成8个随机数,那么可能会有一个重复。(注意,这只适用于p(n)值高达1/2)。

在您的情况下,对于任何特定的随机值(5、6、7、8、9、10、11、12),都有8个可能的值,因此您只需要生成sqrt(8) = 2.83个数字,就有可能有50%的重复。换句话说,生日悖论预测,你只需要生成大约3个数字,这样你就有可能得到一个副本。

另请参见本问答。

还有一点:当心赌徒的谬论,在这个谬论中,人们假设如果你随机生成一个10,那么下一个概率就不会是10。事实上,考虑到你生成的是随机数,任何一个特定数字的概率都是1/8,不管之前的数字是什么。换句话说,如果生成一个12,下一个10的概率是1/8。如果生成7,则下一个数字为10的几率为1/8。如果生成一个10,下一个10的概率仍然是1/8。每个数字都是一个独立的事件(即,到目前为止生成的数字对未来数字的概率分布影响最小)。

tl;dr您需要生成的数字比您认为的要少得多,然后才有可能开始复制-如果您在一个小范围内生成随机数,特别是(像您这样)这个数字特别低。