繁体   English   中英

预测Javascript的Math.random的种子

[英]Predict the Seed of Javascript's Math.random

好的,所以我正在研究如何使用Math.random方法生成随机数。 到目前为止,我学会了它从一个“随机”种子开始,并将该种子插入到一些复杂的方程中以创建一个随机数。 如果种子总是一样,结果总是一样吗?

我听说Math.random的种子是通过当前时间生成的,这是正确的吗? 他们必须使用当前时间一直到mili-seconds或其他东西,因为如果你没有,你会得到相同的结果。

种子究竟是什么? 是“10:45”之类的时间,还是“10月11日10:45”或某种组合的时间和日期?

我怎样才能找到种子,所以我可以预测输出?

我希望能够插入这个:

alert(Math.floor((Math.random()*10)+1));

进入我的网址栏,并能够预测结果。 那可能吗?

我浏览了Rhino 源代码 ,找出他们使用的伪随机函数。 显然,它们回退到 Java标准库中定义的Math.random函数。

Math.random的文档说:

返回带有正号的double值,大于或等于0.0且小于1.0。 返回值是伪随机选择的,具有来自该范围的(近似)均匀分布。

首次调用此方法时,它会创建一个新的伪随机数生成器,就像表达式一样

new java.util.Random

此后,此新伪随机数生成器用于对此方法的所有调用,并且在其他任何地方都不使用。

此方法已正确同步,以允许多个线程正确使用。 但是,如果许多线程需要以很高的速率生成伪随机数,则可以减少每个线程拥有自己的伪随机数生成器的争用。

所以我检查了java.util.Random的文档并找到了这个 (对于默认的构造函数):

创建一个新的随机数生成器。 其种子初始化为基于当前时间的值:

public Random() { this(System.currentTimeMillis()); }

在同一毫秒内创建的两个随机对象将具有相同的随机数序列。

所以现在我们确定种子是以毫秒为单位的当前时间。 此外, 第二个构造函数的文档说:

使用单个长种子创建新的随机数生成器:

public Random(long seed) { setSeed(seed); }

由旁边的方法用于保持伪随机数生成器的状态。

setSeed方法的文档说:

使用单个长种子设置此随机数生成器的种子。 setSeed的一般契约是它改变了这个随机数生成器对象的状态,以便与刚刚用参数种子作为种子创建的状态完全相同。 方法setSeed由Random类实现,如下所示:

synchronized public void setSeed(long seed) {
    this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
    haveNextNextGaussian = false;
}

类Random的setSeed的实现恰好只使用给定种子的48位。 然而,通常,重写方法可以使用长参数的所有64位作为种子值。 注意:虽然种子值是AtomicLong,但仍必须同步此方法以确保hasNextNextGaussian的正确语义。

用于生成随机数的实际方法nextDouble

返回下一个伪随机数,从此随机数生成器的序列中均匀分布介于0.0和1.0之间的double值。

nextDouble函数的实现如下:

public double nextDouble() {
    return (((long)next(26) << 27) + next(27))
        / (double)(1L << 53);
}

显然它取决于 next功能:

生成下一个伪随机数。 子类应该覆盖它,因为所有其他方法都使用它。

next功能的实现如下:

synchronized protected int next(int bits) {
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
    return (int)(seed >>> (48 - bits));
}

那是你正在寻找的伪随机函数。 正如文档中所述:

这是一个线性同余伪随机数发生器,由DH Lehmer定义并由Donald E. Knuth在The Computer of Computer Programming,Volume 2:Seminumerical Algorithms,3.2.1节中描述。

但请注意,这只是Rhino使用的随机数生成器。 其他实现如Spidermonkey和V8可能有自己的伪随机数生成器。

种子可能比毫秒计数更多,因为你可以在相同的毫秒内多次调用Math.random(),并且每次都会返回不同的值。

for (var i = 0; i < 3; i++) {
    console.log(Math.random(), (new Date()).getTime());
};

我的输出:

0.0617244818713516 1352433709108
0.8024995378218591 1352433709108
0.2409922298975289 1352433709108

如果我正在实现它,我可能会根据毫秒计数生成初始种子,然后在每次调用时添加1,这样您就不会获得两次相同的种子值。

这是一种100%准确的方法来预测Math.random()的输出:

Math.random = function () { return .5; };

现在Math.random()将始终返回.5

种子是一个数值,所以我的猜测是,如果你调用Date.now() (或旧的浏览器的new Date().getTime() ,它将是你得到的。

但是,我不确定何时使用该种子,或者种子是否被隔离到当前页面或整个浏览器进程是否共同。 预测随机数应该是非常困难或不可能的,这就是它们的随机性。

不,你无法预测种子,但你可以预先生成足够的数字,以便准确地强制匹配。

无论如何,通过阅读RNG的维基页面开始 - http://en.wikipedia.org/wiki/Random_number_generation ,看看PRNG的实际实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM