Вопрос: Странное поведение при посеве Java Random


Следующий код должен создавать два случайных объекта с одинаковыми семенами:

System.out.println("System time before: " + System.currentTimeMillis());
Random r1 = new Random();
Random r2 = new Random(System.currentTimeMillis());
System.out.println("System time after: " + System.currentTimeMillis());

System.out.println("r1: " + r1.nextInt());
System.out.println("r2: " + r2.nextInt());

Семена должны быть одинаковыми, поскольку System.currentTimeMillis() не изменилось до и после создания двух объектов, как показано на выходе:

System time before: 1331889186449
System time after: 1331889186449
r1: -1836225474
r2: 2070673752

В документах конструктор без аргументов просто:

public Random() { this(System.currentTimeMillis()); }

Так что же дает? Может ли кто-нибудь объяснить, почему два генератора возвращают разные результаты, когда у них должно быть одно и то же семя?


4


источник


Ответы:


Если вы используете java.util.Random, это конструктор no-args по умолчанию, который я вижу - теперь это может зависеть от версии JDK, которую вы используете (этот код, по-видимому, используется для Sun JDK 6 и 7):

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

И просто чтобы подтвердить это, вот код, чтобы проверить, идентичны ли семена:

public static void main(String args[]) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    System.out.println("System time before: " + System.currentTimeMillis());
    Random r1 = new Random();
    Random r2 = new Random(System.currentTimeMillis());
    System.out.println("System time after: " + System.currentTimeMillis());

    Field seed = Random.class.getDeclaredField("seed");
    seed.setAccessible(true);
    AtomicLong seed1 = (AtomicLong) seed.get(r1);
    AtomicLong seed2 = (AtomicLong) seed.get(r2);

    System.out.println("seed1 = " + seed1);
    System.out.println("seed2 = " + seed2);
}

7



Я не думаю, что конструктор по умолчанию делает то, что вы говорите (т. Е. public Random { this(System.currentTimeMillis()); } Документация java просто говорит, что она инициализирует класс со значением, которое, вероятно, будет отличаться при каждом вызове Вот , Глядя в заголовке в моей реализации Random (Mac OS X)

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

2



два генератора возвращают разные выходы, когда у них должно быть одно и то же семя?

они делают? мне кажется, что только один из ваших генераторов получает семя миллиса ...


0