I have two options of code:
Option 1
int myFunc() {
return new Random().nextInt();
}
Or:
Option 2
My real question is whether option 1 is mathematically valid.
Lets start with option 2. The random number generator used by java.util.Random
is specified in the javadoc as follows:
The class uses a 48-bit seed, which is modified using a linear congruential formula. (See Donald Knuth, The Art of Computer Programming, Volume 2, Section 3.2.1.)
and there is more specific detail in the various methods' javadocs.
But the point is that we are using a sequence generated by a linear congruential formula, and such formulae have a significant degree of auto-correlation ... which could be problematic.
Now with option 1, you are using a different Random
instance with a new seed each time, and applying one round of the LC formula. Thus you are getting a sequence of numbers that are likely to be autocorrelated with the seeds. However, the seeds are generated in different ways, depending on the Java version.
Java 6 does this:
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
... which is not very random at all. If you created Random
instances at a constant interval, the seeds are likely to be closely spaced, and therefore the sequence of random numbers produced by your option #1 are liable to be auto-correlated.
By contrast, Java 7 and 8 do this:
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;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
The sequence of seeds produced by the above are likely be a much better approximation to (true) randomness. That probably makes your option #1 superior to option #2.
The downside of your option #1 in Java 6 through 8 is that the System.nanoTime()
probably call involves a system call. That is relatively expensive.
So the short answer is that it is Java version specific which of option #1 and option #2 produces better quality "random" numbers ... from a mathematical perspective.
In both cases, the distribution of numbers will be uniform over a large enough sample size, though I'm not sure it is meaningful to talk about probability distributions when the process is deterministic.
However, neither approach would be suitable as a "crypto strength" random number generator.