我认为你有点误会了......让我试着用我看到的方式来描述算法:
首先,假设nextInt(big)(nextInt,而不是nextLong)能够正确地生成0(包括)和big(不包括)之间分布良好的值范围。
此nextInt(int) 函数用作nextLong(long) 的一部分
因此,该算法通过循环工作,直到该值小于 Integer.MAX_INT,此时它使用nextInt(int)。更有趣的是它在这之前做了什么……
从数学上讲,如果我们取一个数字的一半,减去它的一半,然后减去一半的一半,然后再减去一半的一半,等等,我们这样做的次数足够多,它就会趋于零。类似地,如果你取一个数字的一半,并将它加到一半的一半,等等,它会趋向于原始数字。
算法在这里所做的是它需要一半的数字。通过进行整数除法,如果数字是奇数,则有一个“大”的一半和一个“小”的一半。算法“随机”选择其中一半(大或小)。
然后,它随机选择添加那一半,或者不添加那一半到输出中。
它不断将数字减半并(可能)添加一半,直到一半小于 Integer.MAX_INT。此时,它只计算 nextInt(half) 值并将其添加到结果中。
假设最初的 long 限制远大于Integer.MAX_VALUE,那么最终结果将获得 nextInt(int) 的所有好处,因为它具有至少 32 位状态以及 2 位状态的大 int 值对于Integer.MAX_VALUE 以上的所有高位。
原始限制越大(越接近 Long.MAX_VALUE),循环迭代的次数就越多。在最坏的情况下,它将经过 32 次,但对于较小的限制,它将经过更少的次数。在最坏的情况下,对于非常大的限制,您将获得用于循环的 64 位随机性,然后nextInt(half) 也需要任何东西。
编辑:WalkThrough 添加 - 计算结果的数量更难,但是,从 0 到 Long.MAX_VALUE - 1 的所有 long 值都是可能的结果。使用nextLong(0x4000000000000000) 的“证明”是一个很好的例子,因为所有的减半过程都是偶数,并且设置了第 63 位。
因为设置了第 63 位(可用的最高有效位,因为 bit64 会使数字变为负数,这是非法的)这意味着我们将在值 half 将是 0x0000000004000000....)。因为减半和位移是同一个过程,所以它认为有尽可能多的一半要做,就像最高位集和第 31 位之间的差一样。63 - 31 是 32,所以我们将事情减半 32 次,因此我们做了 32在while循环中循环。 0x4000000000000000 的初始起始值意味着当我们将值减半时,一半中只会设置一个位,并且它将“走”该值 - 每次循环都向右移动 1。
因为我仔细选择了初始值,所以很明显,在while循环中,逻辑本质上是决定是否设置每个位。它取输入值的一半(即 0x2000000000000000)并决定是否将其添加到结果中。让我们假设我们所有的循环都决定将一半添加到偏移量,在这种情况下,我们从偏移量 0x0000000000000000 开始,然后每次通过循环我们添加一半,这意味着每次我们添加:
0x2000000000000000
0x1000000000000000
0x0800000000000000
0x0400000000000000
.......
0x0000000100000000
0x0000000080000000
0x0000000040000000 (this is added because it is the last 'half' calculated)
此时,我们的循环已经运行了 32 次,它已经“选择”将值相加 32 次,因此值中至少有 32 个状态(如果计算大/小一半决策,则为 64)。实际偏移量现在为0x3fffffffc0000000(从 62 到 31 的所有位都已设置)。
然后,我们调用 nextInt(0x40000000),幸运的是,它使用 31 位状态生成结果 0x3fffffff。我们将此值添加到我们的偏移量并得到结果:
0x3fffffffffffffff
通过nextInt(0x40000000) 结果的“完美”分布,我们将完美地覆盖0x7fffffffc0000000 到0x3fffffffffffffff 的值,没有间隙。在我们的while循环中具有完美的随机性,我们的高位将是0x0000000000000000到0x3fffffffc0000000的完美分布结合起来,从0到我们的极限(不包括)0x4000000000000000的完全覆盖
使用来自高位的 32 位状态,以及来自nextInt(0x40000000) 的(假设的)最少 31 位状态,我们有 63 位状态(如果算上大/小一半的决定,则更多),并且完全覆盖。