Is java.util.Random really that random? How can I generate 52! (factorial) possible sequences?

前端 未结 9 1954
-上瘾入骨i
-上瘾入骨i 2020-12-22 15:56

I\'ve been using Random (java.util.Random) to shuffle a deck of 52 cards. There are 52! (8.0658175e+67) possibilities. Yet, I\'ve found out that the seed for

相关标签:
9条回答
  • 2020-12-22 16:26

    Your analysis is correct: seeding a pseudo-random number generator with any specific seed must yield the same sequence after a shuffle, limiting the number of permutations that you could obtain to 264. This assertion is easy to verify experimentally by calling Collection.shuffle twice, passing a Random object initialized with the same seed, and observing that the two random shuffles are identical.

    A solution to this, then, is to use a random number generator that allows for a larger seed. Java provides SecureRandom class that could be initialized with byte[] array of virtually unlimited size. You could then pass an instance of SecureRandom to Collections.shuffle to complete the task:

    byte seed[] = new byte[...];
    Random rnd = new SecureRandom(seed);
    Collections.shuffle(deck, rnd);
    
    0 讨论(0)
  • 2020-12-22 16:27

    Short solution which is essentially the same of dasblinkenlight:

    // Java 7
    SecureRandom random = new SecureRandom();
    // Java 8
    SecureRandom random = SecureRandom.getInstanceStrong();
    
    Collections.shuffle(deck, random);
    

    You don't need to worry about the internal state. Long explanation why:

    When you create a SecureRandom instance this way, it accesses an OS specific true random number generator. This is either an entropy pool where values are accessed which contain random bits (e.g. for a nanosecond timer the nanosecond precision is essentially random) or an internal hardware number generator.

    This input (!) which may still contain spurious traces are fed into a cryptographically strong hash which removes those traces. That is the reason those CSPRNGs are used, not for creating those numbers themselves! The SecureRandom has a counter which traces how many bits were used (getBytes(), getLong() etc.) and refills the SecureRandom with entropy bits when necessary.

    In short: Simply forget objections and use SecureRandom as true random number generator.

    0 讨论(0)
  • 2020-12-22 16:29

    If you consider the number as just an array of bits (or bytes) then maybe you could use the (Secure)Random.nextBytes solutions suggested in this Stack Overflow question, and then map the array into a new BigInteger(byte[]).

    0 讨论(0)
提交回复
热议问题