这是我不明白的code:
// Divide n by two until small enough for nextInt. On each
// iteration (at most 31 of them but usually much less),
什么?对于随机选择的n
我的琐事simulation,我可以进行32
次迭代,31
是平均值。
// randomly choose both whether to include high bit in result
// (offset) and whether to continue with the lower vs upper
// half (which makes a difference only if odd).
这是有道理的。
long offset = 0;
while (n >= Integer.MAX_VALUE) {
int bits = next(2);
为这两个决定获得两位,这是有道理的。
long half = n >>> 1;
long nextn = ((bits & 2) == 0) ? half : n - half;
此处,n
为n/2.0
向上或向下四舍五入,很好。
if ((bits & 1) == 0) offset += n - nextn;
n = nextn;
我迷路了。
}
return offset + nextInt((int) n);
我可以看到它生成了一个正确大小的数字,但它看起来相当复杂而且相当慢,我肯定不明白为什么结果应该均匀分布。 1
1 它不能真正均匀分布,因为状态仅为48位,因此它可以生成不超过2 ** 48个不同的数字。绝大多数long
都无法生成,但是显示它的实验可能需要数年时间。
答案 0 :(得分:2)
我认为你有点误会......让我试着用我看到的方式描述算法:
首先,假设nextInt(big)
(nextInt,而不是nextLong)能够正确地生成0
(包括)和big
之间分布良好的值范围(不包括)。
此nextInt(int)
函数用作nextLong(long)
因此,算法通过循环工作,直到值小于Integer.MAX_INT,此时它使用nextInt(int)
。更有趣的是它之前做的事情......
数学上,如果我们取一半的数字,减去它的一半,然后减去一半的一半,然后减半的一半的一半,等等,我们这样做足够的时间它将趋于零。同样地,如果你拿一半的数字,并将它加到半数的一半,等等,它将倾向于原始数字。
算法在这里做的是它需要一半的数量。通过整数除法,如果数字是奇数,那么就有一个大的'一半和一小'半。算法“随机”#39;选择其中一个(大或小)。
然后,它随机选择添加一半,或者不将那一半添加到输出中。
它将数字减半并且(可能)添加一半,直到一半小于Integer.MAX_INT。此时,它只是计算nextInt(half)
值并将其添加到结果中。
假设初始长限远大于Integer.MAX_VALUE
,那么最终结果将获得nextInt(int)的所有好处,对于一个大的int值,至少32位状态,以及2位高于Integer.MAX_VALUE
的所有高位的状态。
原始限制越大(越接近Long.MAX_VALUE),循环迭代次数越多。在最坏的情况下它会变为32次,但是对于较小的限制,它会经历较少的次数。在最坏的情况下,对于非常大的限制,您将获得用于循环的64位随机性,然后是nextInt(half)
所需的任何内容。
编辑:WalkThrough添加 - 计算结果的数量更难,但是,从0
到Long.MAX_VALUE - 1
的所有长值都是可能的结果。作为'证明'使用nextLong(0x4000000000000000)
是一个很好的例子,因为所有的减半过程都是偶数,并且它有63位设置。
因为第63位已设置(最高位可用,因为bit64会使数字为负数,这是非法的),这意味着我们会在值为< = Integer.MAX_VALUE之前将值减半32(即{ {1}} - 当我们到达那里时,我们0x000000007fffffff
将是half
....)因为减半和位移是相同的过程,它认为最高位集和位31之间存在尽可能多的一半.63 - 31是32,所以我们将事物减半32次,因此我们做了32次在while循环中循环。 0x0000000004000000
的初始起始值意味着,当我们将值减半时,一半中只会设置一个位,并且它将会“走”'降低价值 - 每次通过循环向右移1。
因为我仔细选择了初始值,很明显在while循环中逻辑基本上决定是否设置每个位。它占用输入值的一半(即0x2000000000000000)并决定是否将其添加到结果中。让我们假设为了参数,我们所有的循环都决定将一半加到偏移量,在这种情况下,我们从偏移量0x0000000000000000开始,然后每次循环我们加一半,这意味着每次我们添加:
0x4000000000000000
此时我们的循环已经运行了32次,它已经选择了'添加值32次,因此值中至少有32个状态(如果计算大/小半决定,则为64)。实际偏移现在是0x2000000000000000
0x1000000000000000
0x0800000000000000
0x0400000000000000
.......
0x0000000100000000
0x0000000080000000
0x0000000040000000 (this is added because it is the last 'half' calculated)
(设置从62到31的所有位)。
然后,我们调用nextInt(0x40000000),幸运的是,它产生结果0x3fffffff,使用31位状态到达那里。我们将此值添加到偏移量并获得结果:
0x3fffffffc0000000
完美的' 0x3fffffffffffffff
结果的分布我们可以完全覆盖nextInt(0x40000000)
到0x7fffffffc0000000
的值,而且没有间隙。在我们的while循环中具有完美的随机性,我们的高位将是0x3fffffffffffffff
到0x0000000000000000
的完美分布。结合从0到0x3fffffffc0000000
<的限制(不包括)的完全覆盖/ p>
高位的32位状态和0x4000000000000000
的(假定的)最小31位状态,我们有63位状态(如果计算大/小半决定则更多),并且满覆盖。