Distribution of Random Numbers

前端 未结 5 861
孤独总比滥情好
孤独总比滥情好 2021-02-04 17:22

I have two options of code:

Option 1

int myFunc() {
  return new Random().nextInt();
}

Or:

Option 2

5条回答
  •  别跟我提以往
    2021-02-04 17:36

    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.

提交回复
热议问题