我查阅了Rhino 源代码,找到了他们使用的伪随机函数。显然,他们会 回退 到在 Java 标准库 中定义的Math.random
函数。
Math.random
的文档介绍如下:
返回一个正号、大于等于 0.0 且小于 1.0 的 double 值。返回值在该范围内以伪随机方式(大致)均匀分布。
当第一次调用此方法时,它会像表达式一样创建一个新的伪随机数生成器:
new java.util.Random
此后,所有调用此方法的操作将使用这个新的伪随机数生成器,并且不会在其他地方使用它。
为了正确地被多个线程使用,此方法已经被适当同步。然而,如果有许多线程需要以极大的速率生成伪随机数,则对于每个线程拥有自己的伪随机数生成器可能会减少竞争。
因此,我查阅了java.util.Random
的文档并找到了此链接(默认构造函数)。其中写道:
创建一个新的随机数生成器。其种子值基于当前时间进行初始化:
public Random() { this(System.currentTimeMillis()); }
在同一毫秒内创建的两个随机对象将具有相同的随机数序列。现在我们确信种子是以毫秒为单位的当前时间。此外,
第二个构造函数 的文档说明如下:创建一个新的随机数生成器,使用单个长种子。
public Random(long seed) { setSeed(seed); }
用于 next 方法来保存伪随机数生成器的状态。
setSeed
方法的文档如下所述:
使用单个 long 种子设置此伪随机数生成器的种子。setSeed 方法的一般约定是,它会改变此随机数生成器对象的状态,使其状态与使用参数 seed 作为种子刚创建时完全相同。setSeed 方法由 Random 类实现,具体如下:
synchronized public void setSeed(long seed) {
this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
haveNextNextGaussian = false;
}
Random类中的setSeed方法仅使用给定种子的48位。然而,通常情况下,重写的方法可能会使用long类型参数的所有64位作为种子值。注意:尽管种子值是AtomicLong类型,但仍需同步此方法以确保haveNextNextGaussian方法的正确语义。
生成随机数的实际方法是 nextDouble:
从该随机数生成器的序列中返回介于0.0和1.0之间的下一个伪随机、均匀分布的双精度值。
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));
}
这就是您正在寻找的伪随机函数。如文档中所述:
这是一个线性同余伪随机数生成器,由D.H. Lehmer定义,并由Donald E. Knuth在计算机程序设计艺术第二卷:半数值算法3.2.1节中描述。
请注意,这只是Rhino使用的随机数生成器。其他实现如Spidermonkey和V8可能有自己的伪随机数生成器。
Math.random()
的整个意义在于你无法预测它(至少不是轻易能做到的)。 - Niet the Dark Absolv8
源代码,能否给我们一个确定的答案? - TiansHUo