我编写了模拟骰子滚动的程序
Random r = new Random();
int result = r.nextInt(6);
System.out.println(result);
我想知道是否有办法预测"下一个生成的数字以及JVM如何确定下一个要生成的数字?
我的代码会在任何JVM和操作系统上输出接近真实随机数的数字吗?
答案 0 :(得分:14)
他们是伪随机数,这意味着对于一般意图和目的,他们足够随意。然而,它们是确定性的并且完全依赖于种子。以下代码将两次打印相同的10个数字。
Random rnd = new Random(1234);
for(int i = 0;i < 10; i++)
System.out.println(rnd.nextInt(100));
rnd = new Random(1234);
for(int i = 0;i < 10; i++)
System.out.println(rnd.nextInt(100));
如果您可以选择种子,您可以先预先计算数字,然后使用相同的种子重置生成器,并且您事先知道出现的数字。
答案 1 :(得分:10)
我想知道是否有办法“预测”下一个生成的数字以及JVM如何确定下一个生成的数字?
绝对。 Random
类实现为线性同余数生成器(LCNG)。线性同余生成器的通用公式为:
new_state = (old_state * C1 + C2) modulo N
Random
使用的精确算法在javadocs中指定。如果您知道生成器的当前状态,则下一个状态是完全可预测的。
我的代码会在任何JVM和操作系统上输出接近真实随机数的数字吗?
如果使用Random
,则编号不适用于任何操作系统上的任何JVM。
LCNG产生的序列绝对不是随机的,并且具有与真随机序列显着不同的统计特性。 (序列将强烈自动关联,如果您将连续调用的结果绘制为Random.nextInt()
,则会显示此序列。)
这是一个问题吗?那取决于你的应用程序需要什么。如果您需要难以预测的“随机”数字(例如,对于与安全性相关的算法),那么显然没有。如果这些数字将用于蒙特卡罗模拟,那么LCNG的内部自相关可能会使模拟失真。但是,如果你只是在制作单人纸牌游戏......也许并不重要。
答案 2 :(得分:1)
是的,可以预测随机数生成器接下来会生成什么数字。我已经看到这种情况称为破解,破坏或攻击RNG。搜索任何这些术语以及&#34;随机数生成器&#34;应该会产生很多结果。
阅读How We Learned to Cheat at Online Poker: A Study in Software Security,获取有关如何攻击随机数生成器的出色第一手资料。总而言之,作者根据在线扑克网站采用的错误改组算法找出了使用RNG的原因。然后他们通过抽样处理手来计算出RNG种子。一旦他们拥有了算法和种子,他们就会知道在后来的洗牌之后如何安排牌组。
您也可以参考此link。
答案 3 :(得分:1)
检查How does java.util.Random work and how good is it?:
换句话说,我们从一些开始或'#34;种子&#34;开始。数字 理想情况下是真正无法预测的,并且实际上是 &#34;不可预测&#34;。例如,毫秒数或 甚至纳秒 - 自计算机开机以来就可以使用 大多数系统。然后,每次我们想要一个随机数,我们乘以 当前种子由一些固定数字,a,添加另一个固定数字,c, 然后将结果模数为另一个固定数,m。数字是 一般都很大。这种随机数生成方法又回来了 几乎到了计算的曙光1。几乎每一个&#34;休闲&#34; 您可以想到的随机数发生器 - 来自科学的 计算器到20世纪80年代家用电脑到当天的C和Visual Basic 库函数 - 使用上面公式的一些变体来生成 它的随机数。