Random.nextBoolean()始终返回True无关紧要种子

时间:2015-04-06 16:59:27

标签: java loops random boolean

当我运行以下代码时,无论我使用for循环的范围,代码总是打印出true十次。

public static void main(String[] args) 
{
    Random bool = new Random();

    for (int i = 0; i < 10; i++) {
        bool.setSeed(i);
        System.out.println(bool.nextBoolean());
    }
}

但是,如果我对代码稍作更改并让随机生成器在打印前运行nextBoolean()函数一次,我会在truefalse中正常分布当我改变for循环的范围时,输出变化:

public static void main(String[] args) 
{
    Random bool = new Random();

    for (int i = 0; i < 10; i++) {
        bool.setSeed(i);
        bool.nextBoolean(); //Only change
        System.out.println(bool.nextBoolean());
    }
}

在我看来,nextBoolean()函数在第一次执行时总是返回true,这种行为有什么理由吗?

3 个答案:

答案 0 :(得分:6)

原因可以在setSeed方法的API中找到:

  

按类Random实现setSeed恰好只使用给定种子的48位。

实际上,您提供的long作为种子值乘以固定值(在Random类中私有定义),然后仅考虑最低有效48位。即使这个乘数很大,因为你的i值序列都是连续的,它们都会产生数值相似的种子值。因此,前几千个值实际上被视为与nextBoolean方法具有相同的值,并且您获得完全相同的初始布尔值。再次调用nextBoolean(不再调用setSeed)将重新传输种子值,因此您可以快速远离看到相同的模式。

如果你确实调用setSeed方法,你只需要调用一次,你应该在循环之外这样做。但是Random类完全有能力选择自己的种子值,所以我建议你不要打{{1​​}},除非你知道为什么要这样做。

答案 1 :(得分:1)

所以基本上nextBoolean方法只能返回truefalseseed值的总数可以是[Long.MIN_VALUE, Long.MAX_VALUE]。所以,你可以假设这些种子的一半你会得到true而另一半你会得到false

现在,当您迭代10个数字时,对于这10个种子,您获得的值可能是true。当您尝试相当大的范围时,您更有可能获得两个值的平均分配。

现在每次调用nextBoolean()时,种子都会使用(seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)更新为其他值。因此,如果当前种子为1,则下一个种子将为25214903916,您可以在其中获得truefalse(您不知道)。这就是为什么有时当你在循环中调用false两次时nextBoolean()。毕竟,它是伪随机数生成器。

顺便说一下,你真的不需要调用setSeed()方法。该方法仅用于将种子重置为特定值。 Random类实例本身将以种子值开始,并在每次从中获取值时更新它。你不必担心它。

如果你看到Random类的代码,这就是他们第一次分配种子的方式:

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

所以,你应该把任务留给那个。

答案 2 :(得分:0)

这是我们称之为&#34; psuedorandom&#34;数字。每次随机通话背后都有一个复杂的,通常是不可逆的,但仍然是确定性的功能;通常是一个简单的细胞自动机。对于这么多随机化种子,返回true是这个函数的一个人工产物;为了确保你得到的东西可以说是随机的,我建议使用一个大的变量号,例如来自System.nanoTime()。