为什么181783497276652981和8682522807148012在选择Random.java?
181783497276652981
8682522807148012
Random.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);
因此,new Random()不带任何种子参数的调用将使用当前的“种子唯一化器”并将其与进行异或System.nanoTime()。然后它用于181783497276652981创建另一个要存储的种子唯一化器,以供下次new Random()调用。
new Random()
System.nanoTime()
文字181783497276652981L和8682522807148012L不会放置在常量中,但是它们不会出现在其他任何地方。
181783497276652981L
8682522807148012L
起初,评论给了我一个轻松的线索。在线搜索该文章会产生实际的文章。 8682522807148012没有出现在纸上,但181783497276652981确实出现- 作为另一个号码,一个子1181783497276652981,这是181783497276652981一个1前缀。
1181783497276652981
1
该论文声称,1181783497276652981这个数字对于线性同余生成器具有良好的“优点”。这个数字是否只是被错误地复制到Java中?是否181783497276652981有一个可以接受的优点?
为什么8682522807148012选择了?
在线搜索任何一个数字都不会产生任何解释,只有该页面还注意到1前面的掉落181783497276652981。
是否可以选择其他与这两个数字一样有效的数字?为什么或者为什么不?
这个数字是否只是被错误地复制到Java中?
是的,似乎是一个错字。
181783497276652981是否具有可接受的优点?
这可以使用本文提出的评估算法确定。但是“原始”数字的优点可能更高。
为什么选择8682522807148012?
似乎是随机的。编写代码时可能是System.nanoTime()的结果。
是否可以选择其他与这两个数字一样有效的数字?
并非每个数字都一样“好”。所以不行。
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的用法,而无需添加,无需异或,只需一个乘法即可。
上面提到的论文给出了c = 0和m = 2 ^ 64的良好“乘数”列表,如1181783497276652981。
总而言之:A努力@ JRE-developers;)但是有一个错字。(但谁知道,除非有人对其进行评估,否则丢失的前导1实际上可能会改善播种RNG。)
但是某些乘数肯定更糟:“ 1”导致序列恒定。“ 2”导致单比特移动序列(以某种方式相关)…
RNG的序列间相关实际上与(Monte Carlo)模拟有关,在该模拟中,多个随机序列被实例化甚至并行化。因此,良好的播种策略对于获得“独立”仿真运行是必要的。因此,C ++ 11标准引入了用于生成不相关种子的种子序列的概念。