java为什么允许对nextLong()的底部字进行签名?
java.util.Random
类有一个方法nextLong(),它自己调用next(32),返回一个随机有符号整数
public long nextLong() {
// it's okay that the bottom word remains signed.
return ((long)(next(32)) << 32) + next(32);
}
为什么保持底部单词的签名不会影响随机生成的数字的质量?当构造一个例子时,如果底部字为负值,则生成的长值中间的位被归零。p>
final long INTEGER_MASK = 0xFFFFFFFFL;
int upper = Integer.MAX_VALUE;
int bottom = -1;
System.out.printf("%14s %64s%n","Upper:",Long.toBinaryString(((long)upper << 32)));
System.out.printf("%14s %64s%n","Lower:",Long.toBinaryString((long)bottom));
System.out.printf("%14s %64s%n"," Lower Masked:",Long.toBinaryString(((long)bottom)& INTEGER_MASK));
long result = ((long)upper << 32) + bottom;
System.out.printf("%14s %64s%n","Result:",Long.toBinaryString(result));
//Proper
long resultMasked = ((long)upper << 32) + (((long)bottom & INTEGER_MASK));
System.out.printf("%14s %64s%n%n","Masked",Long.toBinaryString(resultMasked));
Upper: 111_1111_1111_1111_1111_1111_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000
Lower: 1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
Lower Mask: 1111_1111_1111_1111_1111_1111_1111_1111
Result: 111_1111_1111_1111_1111_1111_1111_1110_1111_1111_1111_1111_1111_1111_1111_1111
Masked 111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
目前,较低的字贡献33位,而较高的字只有32位。即使由于32位移位,上面的字是负数,它也不会环绕。我知道javadocs声明:
Because class {@code Random} uses a seed with only 48 bits, this algorithm will not return all possible {@code long} values.
在这种情况下,这可能不是有害的,但例如,gmu的MersenneTwister实现正好使用这个函数调用。这不会影响生成的随机数的质量吗?我错过了什么
# 1 楼答案
正如Jacob G所指出的,低位字贡献32位。不是33位。32位整数(粗略地说)是31位精度加上一个符号位
在这种情况下,我们只是把这31+1位当作位。那么代码是怎么做的,把两个由32个均匀分布的“随机”位组成的序列,连接在一起,得到一个由64个均匀分布的“随机”位组成的序列。。。然后以
long
的形式返回