为什么允许保持nextLong()的底部单词签名?

问题描述 投票:0回答:1

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);
}

如何保持签名的底部字不会影响随机生成的数字的质量?在构造示例时,如果底部字是负的,则在生成的长值的中间位被归零。

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声明:

因为类{@code Random}使用只有48位的种子,所以此算法不会返回所有可能的{@code long}值。

在这种情况下,它可能不是有害的,例如gmu的MersenneTwister实现正好使用了这个函数调用。这不会影响产生的随机数的质量吗?我在这里错过了什么?

java random bit-shift mersenne-twister
1个回答
1
投票

目前,低位字贡献33位,而高位仅有32位。

...

我在这里错过了什么?

正如Jacob G指出的那样,低位字贡献32位。不是33位。 32位整数(粗略地说)是31位精度加一个符号位。

在这种情况下,我们只将31 + 1位视为位。那么代码如何采用32个均匀分布的“随机”位的两个序列,将它们连接在一起,得到64个均匀分布的“随机”位的一个序列......然后它作为long返回。

© www.soinside.com 2019 - 2024. All rights reserved.