Random(Java 7)中的181783497276652981和8682522807148012是什么?

2022-08-31 09:23:08

为什么被选中?1817834972766529818682522807148012Random.java

以下是 Java SE JDK 1.7 的相关源代码:

/**
 * Creates a new random number generator. This constructor sets
 * the seed of the random number generator to a value very likely
 * to be distinct from any other invocation of this constructor.
 */
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

private static final AtomicLong seedUniquifier
    = new AtomicLong(8682522807148012L);

因此,在没有任何种子参数的情况下调用时,将当前的“种子单基化器”与 XOR 进行 XOR。然后,它用于创建另一个种子单一查询器,以供下次调用时存储。new Random()System.nanoTime()181783497276652981new Random()

文本和不放在常量中,但它们不会出现在其他任何地方。181783497276652981L8682522807148012L

起初,评论给了我一个简单的线索。在线搜索该文章会产生实际的文章。 没有出现在论文中,但确实出现了 - 作为另一个数字的子字符串,它前面有一个。868252280714801218178349727665298111817834972766529811817834972766529811

该论文声称,这个数字为线性同余发生器提供了良好的“优点”。这个数字只是被错误地复制到Java中了吗?是否具有可接受的优点?1181783497276652981181783497276652981

为什么被选中?8682522807148012

在线搜索任一数字都不会产生任何解释,只有此页面也注意到在 前面掉落了。1181783497276652981

是否可以选择其他数字与这两个数字一样有效?为什么或为什么不呢?


答案 1
  1. 这个数字只是被错误地复制到Java中了吗?

    是的,似乎是一个错别字。

  2. 181783497276652981有可接受的优点吗?

    这可以使用论文中提出的评估算法来确定。但“原始”数字的优点可能更高。

  3. 为什么选择8682522807148012?

    似乎是随机的。它可能是编写代码时 System.nanoTime() 的结果。

  4. 是否可以选择其他数字与这两个数字一样有效?

    并非每个数字都同样“好”。所以,不。

播种策略

不同版本和 JRE 实现之间的默认种子设定架构存在差异。

public Random() { this(System.currentTimeMillis()); }
public Random() { this(++seedUniquifier + System.nanoTime()); }
public Random() { this(seedUniquifier() ^ System.nanoTime()); }

如果您在一行中创建多个 RNG,则第一个是不可接受的。如果它们的创建时间落在相同的毫秒范围内,它们将给出完全相同的序列。(相同的种子 = >相同的序列)

第二个不是线程安全的。多个线程在同时初始化时可以获得相同的 RNG。此外,后续初始化的种子往往是相关的。根据系统的实际计时器分辨率,种子序列可以线性增加(n,n + 1,n + 2,...)。正如在随机种子需要有多大不同?和参考论文中所述 伪随机数生成器初始化的常见缺陷,相关种子可以在多个RNG的实际序列之间产生相关性。

第三种方法创建随机分布的种子,从而创建不相关的种子,甚至跨线程和后续初始化。所以目前的java文档:

此构造函数将随机数生成器的种子设置为一个很可能与此构造函数的任何其他调用不同的值。

可以通过“跨线程”和“不相关”进行扩展

种子序列质量

但种子序列的随机性仅与底层RNG一样好。在此 Java 实现中,用于种子序列的 RNG 使用 c=0 和 m=2^64 的乘法线性同余生成器 (MLCG)。(模数 2^64 由 64 位长整数的溢出隐式给出)由于零c和2次方模量,“质量”(周期长度,位相关性等)是有限的。正如论文所说,除了整体周期长度之外,每个位都有自己的周期长度,对于不太重要的位,周期长度呈指数级下降。因此,较低的位具有较小的重复模式。(seedUniquifier() 的结果应该在实际 RNG 中被截断为 48 位之前进行位反转)

但它很快!为了避免不必要的比较和设置循环,循环体应该很快。这可能解释了这个特定的MLCG的用法,没有加法,没有xoring,只有一个乘法。

正如1181783497276652981,上述论文列出了c =0和m=2^64的良好“乘数”。

总而言之:A为努力@JRE开发人员;)但是有一个错别字。(但谁知道呢,除非有人评估它,否则缺少的前导1实际上有可能改善种子RNG。

但有些乘数肯定更糟:“1”导致一个恒定的序列。“2”导致单个位移动序列(以某种方式相关)...

RNG的序列间相关性实际上与(蒙特卡罗)模拟相关,其中多个随机序列被实例化甚至并行化。因此,一个好的播种策略对于获得“独立”的模拟运行是必要的。因此,C++11标准引入了种子序列的概念,用于生成不相关的种子。


答案 2

如果您认为用于随机数生成器的方程是:

LCGEquation

其中 X(n+1) 是下一个数字,a 是乘数,X(n) 是当前数字,c 是增量,m 是模数。

如果进一步研究,a、c 和 m 在类的标头中定义。Random

private static final long multiplier = 0x5DEECE66DL;   //= 25214903917 -- 'a'
private static final long addend = 0xBL;               //= 11          -- 'c'
private static final long mask = (1L << 48) - 1;       //= 2 ^ 48 - 1  -- 'm'

并查看该方法,这是方程式已实现protected int next(int bits)

nextseed = (oldseed * multiplier + addend) & mask;
//X(n+1) =  (X(n)   *      a     +    c  ) mod m

这意味着该方法实际上正在获得X(n),或者在第一种情况下初始化X(0),实际上,该值随后被的值进一步修改。该算法与上面的等式一致,但与以下 X(0) = , a = , m = 2 ^ 64 和 c = 0。但是,由于 mod m 是由长溢出预先形成的,因此上述方程正好变成seedUniquifier()8682522807148012 * 181783497276652981System.nanoTime()8682522807148012181783497276652981

eq2

看看这篇论文,a = 的值是 m = 2 ^ 64, c = 0。因此,它似乎只是一个拼写错误和 X(0) 的值,它似乎是从 的旧代码中随机选择的数字。如此处所示。但这些选择的数字的优点可能仍然有效,但正如托马斯B.所提到的,可能不如论文中的“好”。11817834972766529818682522807148012Random

编辑 - 以下原始想法已经澄清,因此可以忽略,但将其留给参考

这就引出了我的结论:

  1. 本文的引用不是针对值本身,而是针对由于a,c和m的值不同而用于获取值的方法。

  2. 这只是巧合,除了前导1之外,该值在其他方面是相同的,并且注释放错了位置(尽管仍然难以相信这一点)

对论文中的表格存在严重的误解,开发人员只是随机选择了一个值,因为当它被乘以时,首先使用表格值的意义是什么,特别是因为您可以以任何方式提供自己的种子值,在这种情况下,这些值甚至没有被考虑在内。

所以回答你的问题

是否可以选择其他数字与这两个数字一样有效?为什么或为什么不呢?

是的,可以使用任何数字,实际上,如果您在实例化随机时指定种子值,则使用的是任何其他值。此值对生成器的性能没有任何影响,这是由类中硬编码的 a,c 和 m 的值确定的。


推荐