Flash
Flash

Reputation: 16703

Weird behaviour when seeding Java Random

The following code should create two Random objects with identical seeds:

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

The seeds should be identical since System.currentTimeMillis() did not change before and after creating the two objects as shown in the output:

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

From the docs, the constructor without any arguments is simply:

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

So what gives? Can anyone explain why the two generators return different outputs when they should have the same seed?

Upvotes: 4

Views: 876

Answers (3)

assylias
assylias

Reputation: 328619

If you are using java.util.Random, this is the default no-args constructor I see - now it might depend on the version of JDK you are using (this code seems to be used for sun JDK 6 & 7 at least):

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

And just to confirm it, here is a code to check if the seeds are identical:

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

Upvotes: 7

Roman Kutlak
Roman Kutlak

Reputation: 2784

I don't think that the default constructor does what you say it does (i.e., public Random { this(System.currentTimeMillis()); } The java documentation just says that it is initialising the class with a value that is likely be different on each invocation here. Looking in a header in my implementation of Random (Mac OS X)

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

Upvotes: 2

Th0rndike
Th0rndike

Reputation: 3436

the two generators return different outputs when they should have the same seed?

they do? it looks to me that only one of your generators is getting the millis seed...

Upvotes: 0

Related Questions