【问题标题】:Random class acting odd?随机班级表现奇怪?
【发布时间】:2012-11-05 23:14:52
【问题描述】:

在这段代码中:

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,所以输出一般应该是随机的。谁能解释一下?

【问题讨论】:

  • @JeremyD 不是真的 - 这个问题每次都会创建一个新的随机对象。
  • “任何考虑产生随机数字的算术方法的人,当然都处于一种犯罪状态。” ——约翰·冯·诺依曼
  • @climbage 如果你不看问题,但第二个答案是正确的答案,和这里提出的一样:)

标签: java random


【解决方案1】:

让它再打印几个,前 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

看起来不错。

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

【讨论】:

  • nathan,如果在线扑克使用蹩脚的 LCG,我会感到震惊。
  • 而且,他们不能这么直率,没有操纵就可以赚到太多钱。
  • 它们让它看起来不错,但它们并没有考虑到所有的可能性。他们确保创造行动的所有可能性都存在,但忽略了现实生活中存在的一些更平凡的套牌,创造更多的兴奋和行动,并为更差的玩家提供更好的机会。
  • @nathanhayfield 赌博中使用的每一次机会游戏都经过精心设计,旨在长期为赌场赢钱,即使赌场公平竞争。在线赌场的大规模运营(与实体赌场相比)几乎保证了持续的利润。
  • 人们对数以百万计的在线扑克手牌进行了严格的统计分析,但从未发现任何证据表明他们所做的只是真正的随机洗牌。此外,这里有三个事实:1. 操纵手的动机非常小, 2. 如果发现它们是一个巨大的抑制因素,以及 3. 有人很容易证明如果是的话,它是被操纵的。简而言之,在线扑克公司绝对不会做这种事情。
【解决方案2】:

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

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

【讨论】:

  • 好的,有道理。谢谢!
  • 排除从/dev/random等来源获取熵的类/方法,什么随机生成器不是伪随机的?
  • 无。我只是想澄清一下这里使用“随机”词可能造成的混淆。通常人们知道他们指的是伪随机(即确定性计算)数字,但这里 OP 似乎期望真正的(非确定性)随机性。
【解决方案3】:

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

【讨论】:

  • 事实上,鉴于long1.8e19 可能的值,因此Random 可以产生序列,很有可能对于每个可能的10 个数字序列都存在一个种子这将使Random 生成它们作为nextInt(10) 的前十个结果。 (留给比我更擅长统计/概率的读者的练习将确定这个的实际概率。或者更确切地说,1.8e19 真正随机选择 10 位数字最终选择了所有可能的 10 位数字序列。)跨度>
【解决方案4】:

随机是一个linear congruential generator;即它基于以下形式的公式:

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

其中 C1、C2 和 M 是常数。

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

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

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


注意事项:

  • Random 不是随机数生成器。它是一个伪随机数字生成器。这意味着,如果您知道初始状态,则生成的数字是完全可以预测的。
  • 对 Random 使用真正的随机种子并没有真正的帮助。这只会使问题更难重现。
  • Random 的其他种子可能会在此特定测试中为您提供类似的模式。
  • 从纯数学的角度来看,十个数字并不比任何其他十个数字的序列更多或更少“随机”。但从数学的角度来看,Random 根本不是随机的。事实上,一旦你弄清楚N 的当前值是多少,这是完全可以预测的。问题在于自相关导致序列在直觉上显得非随机。
  • 如果您想避免这种直观的非随机性,请使用 SecureRandom,它应该是真正的随机数源,或者是更难以预测的伪随机数生成器。

【讨论】:

  • " 实际上,模 10 与生成器的自然周期“共振”" 为什么这个,通常素数用于生成器?
【解决方案5】:

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

这只是一个有趣的巧合。

【讨论】:

  • 连续出现十个1s 的概率与任何其他序列的概率完全相同。
  • @ChristofferHammarström 是的。但是,绝对值很小。 (即,如果您要手动采摘种子,则需要一段时间才能准确找到起始序列。)
  • 这颗种子很可能不是手工采摘的。
  • @AlexWien 实际上,我反驳说它极有可能是。随机数生成器是明确播种的,其数字会产生非常容易识别的句子。您如何想象OP是如何偶然发现的?您无法在不使用反射的情况下访问 Random 实例的种子,因此您假设某人作为“正常”代码的一部分生成小于 10 的整数,并出于某些完全不相关的目的记录序列,并使用生成的每个数字检查种子,以便能够重现这一点。
  • @AlexWien 基本上,我相信任何偶然发现 OP 发现的情况都非常复杂,即不太可能,更有可能有人在寻找“有趣”@ 987654325@故意种子。例如,一位老师试图迷惑/取悦他的学生。
【解决方案6】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多