15

在这段代码中:

Random random = new Random(441287210);
for(int i=0;i<10;i++)
    System.out.print(random.nextInt(10)+" ");
}

输出是1 1 1 1 1 1 1 1 1 1, 每次。

为什么是这样?不Random应该是……嗯……随机的?我认为Random该类使用System.nanoTime,因此输出通常应该是随机的。有人可以解释一下吗?

4

6 回答 6

20

让它再打印几个,前 100 个是

1 1 1 1 1 1 1 1 1 1 3 4 7 2 2 6 0 3 0 2 8 4 1 6 0 0 0 2 8 2 9 8 9 2 5 2 1 1 4 5 3 4 1 4 1
8 7 6 6 0 6 5 0 4 5 5 6 0 8 3 8 9 7 4 0 9 9 7 7 9 3 9 6 4 5 0 6 3 7 4 9 8 7 6 2 8 9 8 4 4
8 4 9 0 1 6 9 6 1 5

看起来不错。

每个好的(伪)随机序列都包含重复数字的条纹,这个以一个开头。

于 2012-11-05T23:19:24.923 回答
14

Random类生成的值是伪随机的:它们是基于种子值使用确定性算法创建的。通常(例如,如果您使用无参数构造函数)种子使用当前时间初始化,这显然是一个唯一值。因此,生成了一个独特的“随机”序列。

在这里,您使用的是在代码执行之间不会改变的常量种子值。因此,您总是得到相同的序列。恰好这个序列是1 1 1 1 1 1 ...针对这个特定的种子的。

于 2012-11-05T23:19:08.020 回答
5

没有什么可以说1连续 10 秒的序列是不可能的。给你种子值的人441287210恰好发现了这样一个值,该值导致1连续 10 秒开始。如果您继续调用nextInt()(即超过 10 次),您将看到随机值。应该有可能找到将导致其他“明显非随机”序列的其他种子值。

于 2012-11-05T23:20:53.290 回答
3

Random 是一个线性同余生成器;即它基于以下形式的公式:

N <- (N * C1 + C2) % M

其中 C1、C2 和 M 是常数。

这类生成器的特性之一是具有高自相关性。事实上,如果您绘制连续的数字,您可以在数字中看到清晰的剥离模式。

您的测试程序有效地从底层生成器中获取了 10 个连续的数字,计算了它们的模 10 的值......并发现它们都是相同的。实际上,模 10 与发电机的自然周期性“共振”……在短时间内。

这是使用具有高自相关性的 PRNG 的缺点之一。用外行的话来说......它“不是很随机”......如果你在随机性至关重要的情况下使用它,你可能会遇到麻烦。


笔记:

  • Random 不是随机数生成器。它是一个伪随机数生成器。这意味着,如果您知道初始状态,则生成的数字是完全可以预测的。
  • 对 Random 使用真正的随机种子并没有真正的帮助。它只会使问题更难重现。
  • Random 的其他种子可能会在此特定测试中为您提供类似的模式。
  • 从纯数学的角度来看,十个数字并不比任何其他十个数字的序列更多或更少“随机”。但从数学的角度来看,Random根本不是随机的。事实上,一旦你弄清楚当前值N是多少,它是完全可以预测的。问题是使序列直观地显示为非随机的自相关。
  • If you want to avoid this kind of intuitive non-randomness, use SecureRandom which should either be a true random number source, or a generator of pseudo-random numbers that are much, much harder to predict.
于 2012-11-05T23:32:03.633 回答
1

如果使用for(int i=0;i<100;i++),则输出的序列再次“更随机”。连续出现十个随机序列的概率1可能很小,但也不是不可能。(只要给定足够的样本,几乎肯定会发生任何序列。)

这只是一个有趣的巧合。

于 2012-11-05T23:20:35.883 回答
0

Random 类在调用 nextInt() 时使用种子生成随机数,建议使用长数,当您创建随机对象时,您提供的 int 不足以满足随机性。

尝试运行循环 20 次,您会看到随机性或移除种子或提供很长的种子值

于 2012-11-05T23:27:22.020 回答