如何获得Random.nextLong可返回的所有可能值


Random#nextLong()文档指出,此方法不会返回所有可能的long值:

返回此随机数生成器序列中的下一个伪随机、均匀分布的长值。nextLong的一般约定是伪随机生成并返回一个长值。方法nextLong由类Random实现,就好像通过:

public long nextLong() {
return ((long) next(32) << 32) + next(32);
}

由于类Random使用只有48位的种子,此算法不会返回所有可能的长值

例如,数字8090327796378429294是可生成的,但数字8090327796378429295不是,尽管它们之间的唯一差异是一个最低有效位,并且值本身是63位长。

有一种方法可以知道nextLong()是否可以使用以下算法返回值:

public class JavaRandom {
private static final long ADD = 0xBL;
private static final long MULT = 0x5DEECE66DL;
private static final long TWO16 = 1L << 16;
private static final long MASK_31 = (1L << 31) - 1;
private static final long MASK_32 = (1L << 32) - 1;
private static final long MASK_48 = (1L << 48) - 1;
public static boolean canBeGeneratedByJavaRandom(long randomValue) {
long i1 = (randomValue >> 32) & MASK_32;
long i2 = (randomValue & MASK_32);
if (i2 > MASK_31) {
i1 = i1 + 1;
}
long front = i1 << 16;
for (long i = 0; i < TWO16; i++) {
long seed = front | i;
long i22 = (((seed * MULT) + ADD) & MASK_48) >> 16;
if (i22 == i2) {
return true;
}
}
return false;
}
}

如果不对每个可能的64位数字运行此检查,如何获取nextLong()可以生成的所有值?在收集到所有值之前调用nextLong()是不合理的,因为可能会发生冲突。

假设setSeed函数完全使用传入值的低48位来设置种子,您可以简单地迭代所有seed值,从0(1L << 48) - 1setSeed到每个值,然后为每个种子调用nextLong()一次。

更多信息:

  • 这个答案指出,可以从两个连续的nextInt()值中确定种子,因此没有两个不同的种子生成相同的两个连续nextInt()
  • 文档指出,nextInt()调用next(32),而nextLong()获得两个连续next(32)值的值

根据以上两点,不同的种子值将生成不同的nextLong()值。

最新更新