How does ThreadLocalRandom.nextLong(long n) work?
这是我不理解的代码:
1 2 | // Divide n by two until small enough for nextInt. On each // iteration (at most 31 of them but usually much less), |
什么?通过随机选择的
1 2 3 | // 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). |
这是有道理的。
1 2 3 |
为这两个决定取两个比特,这是有道理的。
1 2 | long half = n >>> 1; long nextn = ((bits & 2) == 0) ? half : n - half; |
这里,
1 2 | if ((bits & 1) == 0) offset += n - nextn; n = nextn; |
我迷路了。
1 2 | } return offset + nextInt((int) n); |
我可以看到它生成了一个适当大小的数字,但它看起来相当复杂,速度相当慢,我肯定不明白为什么结果应该是均匀分布的。1
它不能真正均匀分布,因为状态只有48位,所以它可以生成不超过2*48个不同的数字。绝大多数的
我觉得你有点错了……让我试着用我看到的方式来描述算法:好的。
首先,假设
此
因此,该算法通过循环工作,直到值小于integer.max_int,此时它使用
从数学上讲,如果我们取半个数,减去它的一半,然后减去一半的一半,再减去一半的一半的一半,等等,这样做足够多次,它就会趋向于零。同样地,如果你取一个数的一半,把它加到一半的一半,等等,它将趋向于原始数。好的。
这里的算法只需要一半的数字。通过做整数除法,如果数字是奇数,那么有一个"大"一半和一个"小"一半。算法"随机"选择其中的一部分(大的或小的)。好的。
然后,它随机选择添加这一半,或者不将这一半添加到输出。好的。
它不断地将数字减半,并(可能)添加一半,直到一半小于integer.max int。此时,它只需计算
假设初始长限比
原始限制越大(越接近long.max_值),循环迭代的次数越多。在最坏的情况下,这将是32次,但对于较小的限制,它将经历较少的次数。在最坏的情况下,对于非常大的限制,您将得到用于循环的64位随机性,然后得到
编辑:Walkthrough增加了计算结果数量的难度,但是,从
因为设置了位63(因为位64会使数字变为负数,这是非法的,所以最有效的位),这意味着在值<=integer.max_value(即
因为我仔细选择了初始值,很明显在while循环中,逻辑基本上决定是否设置每个位。它需要输入值的一半(即0x20000000000),并决定是否将其添加到结果中。为了论证起见,我们假设所有的循环都决定将一半添加到偏移量中,在这种情况下,我们从偏移量0x0000000000000000开始,然后每次通过循环添加一半,这意味着每次添加:好的。
1 2 3 4 5 6 7 8 | 0x2000000000000000 0x1000000000000000 0x0800000000000000 0x0400000000000000 ....... 0x0000000100000000 0x0000000080000000 0x0000000040000000 (this is added because it is the last 'half' calculated) |
此时,循环已经运行了32次,它"选择"了32次添加值,因此在值中至少有32个状态(如果计算大小一半的决策,则为64)。实际偏移量现在为
然后,我们称之为nextint(0x40000000),幸运的是,它会产生结果0x3ffffff,使用31位状态到达那里。我们将此值添加到偏移量中,得到结果:好的。
1 | 0x3fffffffffffffff |
如果
从高位得到32位的状态,从