随机(Java 7)中的181783497276652981和8682522807148012有什么?
为什么在181783497276652981
select了Random.java
和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
创build另一个种子uniquifier被存储下一次new Random()
被调用。
文字181783497276652981L
和8682522807148012L
不放置在常量中,但不会出现在其他地方。
起初评论给了我容易的领导。 在线search该文章会得到实际的文章 。 8682522807148012
没有出现在文件中,但181783497276652981
确实出现 – 作为另一个数字的子串, 1181783497276652981
,这是181783497276652981
与1
前置。
这篇文章宣称1181783497276652981
是一个可以产生线性同余发生器的“优点”的数字。 这个数字是否被错误地复制到Java中? 181783497276652981
有一个可以接受的优点吗?
为什么select8682522807148012
?
在网上search任何一个号码都不会得到解释,只有这个页面也会注意到在181783497276652981
前面掉落的1
。
其他数字是否可以和这两个数字一起工作呢? 为什么或者为什么不?
-
这个数字是否被错误地复制到Java中?
是的,似乎是一个错字。
-
181783497276652981有一个可以接受的优点吗?
这可以使用本文提出的评估algorithm来确定。 但“原始”号码的价值可能更高。
-
为什么select8682522807148012?
似乎是随机的。 编写代码时可能是System.nanoTime()的结果。
-
其他数字是否可以和这两个数字一起工作呢?
并不是每个数字都是同样“好”的。 所以不行。
播种策略
不同版本的默认种子模式和JRE的实现有所不同。
public Random() { this(System.currentTimeMillis()); }
public Random() { this(++seedUniquifier + System.nanoTime()); }
public Random() { this(seedUniquifier() ^ System.nanoTime()); }
如果您连续创build多个RNG,则第一个是不可接受的。 如果它们的创build时间落在相同的毫秒范围内,它们将会给出完全相同的序列。 (相同的种子=>相同的序列)
第二个不是线程安全的。 多个线程同时初始化时可以得到相同的RNG。 另外,后续初始化的种子往往是相关的。 根据系统的实际定时器分辨率,种子序列可以线性增加(n,n + 1,n + 2,…)。 正如随机种子需要有多大差异所述? 以及引用的论文中关于伪随机数发生器初始化中的Common缺陷 ,相关的种子可以在多个RNG的实际序列之间产生相关性。
第三种方法创build随机分布的,因此不相关的种子,甚至跨线程和随后的初始化。 所以目前的Java文档:
这个构造函数将随机数生成器的种子设置为一个非常可能不同于此构造函数的任何其他调用的值。
可以通过“跨线程”和“不相关”
种子序列质量
但是播种序列的随机性只和潜在的RNG一样好。 在这个Java实现中用于种子序列的RNG使用了一个乘法线性同余发生器(MLCG),其中c = 0和m = 2 ^ 64。 (模数2 ^ 64由64位长整数的溢出隐含给出)由于零c和2模的幂,所以“质量”(循环长度,位相关…)是有限的。 正如文章所说,除了整个周期长度外,每一个比特都有一个自己的周期长度,对于较低有效位以指数级递减。 因此,低位具有较小的重复模式。 (seedUniquifier()的结果在实际的RNG中被截断为48位之前应该进行位反转)
但速度很快! 为了避免不必要的比较和设置循环,循环体应该是快速的。 这可能解释了这个特定的MLCG的使用,没有另外,没有xoring,只是一个乘法。
上述论文给出了一个好的“乘数”列表,其中c = 0和m = 2 ^ 64,分别为1181783497276652981。
总而言之:A for JRE开发者;)但是有一个错字。 (但是谁知道,除非有人评估,否则有可能导致失踪的领先1实际上改善了播种RNG。)
但是有些乘数肯定更糟糕:“1”会导致一个不变的序列。 “2”导致一个单位移动序列(以某种方式相关)…
RNG的序列间相关性实际上与(蒙特卡罗)模拟相关,其中多个随机序列被实例化并且甚至并行化。 因此,一个好的播种策略是必要的,以获得“独立”的模拟运行。 因此,C ++ 11标准引入了用于生成不相关种子的种子序列的概念。
如果你认为用于随机数发生器的公式是:
其中X(n + 1)是下一个数,a是倍数,X(n)是当前数,c是增量,m是模数。
如果进一步查看Random
,则在类的头部定义a,c和m
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
这意味着seedUniquifier()
方法实际上获得了X(n),或者在实际上是8682522807148012 * 181783497276652981
初始化X(0)的第一种情况下,该值再乘以System.nanoTime()
的值。 该algorithm与上面的等式一致,但是具有以下X(0)= 8682522807148012
,a = 181783497276652981
,m = 2 ^ 64和c = 0。但是,由于长模式的长模式溢出,
看这篇文章 ,a = 1181783497276652981
的值是m = 2 ^ 64,c = 0。所以它看起来只是一个错字,值为8682522807148012
X(0)看起来似乎是随机select的一个数字遗留的Random
代码。 如这里所见。 但是,这些select的数字的优点仍然是有效的,但如托马斯·B所提到的那样,可能并不像文中那样“好”。
编辑 – 低于原来的想法已经澄清,所以可以忽略,但留作参考
这导致了我的结论:
-
本文的参考不是针对数值本身,而是针对由于a,c和m的不同值而获得数值的方法
-
仅仅是巧合的是,价值是否与领先1相同,而评论是错误的(尽pipe如此,仍然在努力相信这一点)
要么
在这篇文章中,人们对表格有一个严重的误解,开发者只是随机select了一个数值,在乘数的时候,首先使用表格的值是什么,特别是你可以提供你的以任何方式拥有种子价值,在这种情况下甚至不考虑这些价值
所以要回答你的问题
其他数字是否可以和这两个数字一起工作呢? 为什么或者为什么不?
是的,可以使用任何数字,实际上,如果您在Instantiate Random中指定种子值,则使用任何其他值。 这个值对发生器的性能没有任何影响,这是由类内硬编码的a,c和m的值决定的。
根据你提供的链接,他们select了( 在添加缺less的1 :)后 )最好的收益从2 ^ 64,因为长不能有2 ^ 128