Overview:
This article describes two random number implementation methods of jdk to understand its operating mechanism. And compare the running efficiency. However, the two types of random numbers still have certain security risks (pseudo-random numbers may be guessed as random sequences). Finally, another safer method for generating random numbers is provided. The appendix also provides code analysis for the jdk nextInt (n) function.
I. Two production methods:
Generally, jdk is used to obtain 0 ~ The Random Number of N (N is a natural number) can be obtained in the following two ways:
1. Math. random () -- returns a random decimal number of [0, 1). the random number of [0, n) can be obtained through (int) (n * Math. random ().
2. The nextInt (n) method of java. util. Random -- returns a Random decimal number of [0, n ).
In jdk1.6 implementation, Math. random () is implemented as follows:
[Java]
Public static double random (){
If (randomNumberGenerator = null) initRNG (); // randomNumberGenerator is the Random class Singleton held in Math.
Return randomNumberGenerator. nextDouble ();
}
RandomNumberGenerator implements random Number Generation Based on the original Math. Random () class.
Next, let's look at how to implement the nextDouble () and nextInt (n) of the Random class:
[Java]
Public double nextDouble (){
Return (long) (next (26) <27) + next (27 ))
/(Double) (1L <53 );
}
[Java] view plaincopy
Public int nextInt (int n ){
If (n <= 0)
Throw new IllegalArgumentException ("n must be positive ");
If (n &-n) = n) // I. e., n is a power of 2
Return (int) (n * (long) next (31)> 31 );
Int bits, val;
Do {
Bits = next (31 );
Val = bits % n;
} While (bits-val + (n-1) <0); // For the reason, see Appendix.
Return val;
}
From the two programs, we can see that the generation of random numbers still depends on next (n ).
(Note: The next (n) function is to generate n bits, each bit is random 0 or 1, when n <32, next (n) the random number range is 0 ~ 2 ^ 31-1. When n = 32, a random number ranging from-2 to the power of 31 is generated ~ 2 ^ 31-1. The next function in the source code finally returns return (int) (nextseed >>> (48-bits) because the Random Seed is 48 bits, the final return is the high n-bit of the Random Seed)
In nextDouble (), China Railway calls next (n) twice, while nextInt (n) does not, but the average calls next (n) the number of times is less than 2 (see appendix B ). Therefore, nextInt (n) is more efficient than nextDouble () to obtain random numbers.
In addition, the integer random number obtained through (int) (n * Math. random () is actually approximate by the double random number, and the accuracy should be lower than nextInt (n.
2. Comparison of Running Speed:
[Java]
Public class RandomTest {
Static Random random = new Random ();
Static int r1 (int n ){
Return (int) (Math. random () * n );
}
Static int r2 (int n ){
Return random. nextInt (n );
}
Public static void main (String [] args ){
Long t1 = System. nanoTime ();
For (int I = 0; I <10000; I ++ ){
R1 (1024 );
}
Long t2 = System. nanoTime ();
System. out. println (t2-t1 );
T1 = System. nanoTime ();
For (int I = 0; I <10000; I ++ ){
R2 (1024 );
}
T2 = System. nanoTime ();
System. out. println (t2-t1 );
}
}
Result:
3422502
1335365
Conclusion: nextInt (n) is better than Math. random () Regardless of accuracy and efficiency.
Iii. Security
The next (n) method of the Random class calculates the value of nextseed (the 48-bit of seed) based on the determined seed. Despite various operations, however, the results are still linear and predictable.
[Java]
Protected int next (int bits ){
Long oldseed, nextseed;
AtomicLong seed = this. seed;
Do {
Oldseed = seed. get ();
Nextseed = (oldseed * multiplier + addend) & mask;
} While (! Seed. compareAndSet (oldseed, nextseed ));
Return (int) (nextseed >>> (48-bits ));
}
As you can see from the program, as long as the seed is determined, the nextseed is determined, and the entire sequence can be reconstructed. Therefore, if an attacker obtains the initial seed for a random scenario, the attacker can easily simulate a random number and obtain the next seed. Or he uses the exhaustive seed to obtain the calculated random number to match the random number of the program.
Therefore, java. security. SecureRandom can be used for random number scenarios with security requirements. Replace the pseudo-Random class. This class inherits from the Random class and overwrites the next (n) function. Therefore, we can use its strongly Random Seed algorithm (SHA1PRNG) to generate Random numbers.
There must be a loss in efficiency, which is about one order of magnitude different.
[Java]
Static int r3 (int n ){
Final int offset = 123456; // offset is a fixed value to avoid being guessed as the seed source (similar to the addition of salt in cryptography)
Long seed = System. currentTimeMillis () + offset;
SecureRandom secureRandom1;
Try {
SecureRandom1 = SecureRandom. getInstance ("SHA1PRNG ");
SecureRandom1.setSeed (seed );
Return secureRandom1.nextInt ();
} Catch (NoSuchAlgorithmException e ){
// TODO Auto-generated catch block
E. printStackTrace ();
}
Return 0;
}
Iv. Appendix
A. nextInt (n) function Parsing
This function maps the result of the 31-Bit Original random range next (31) to the range of [0, n. However, without special processing, the probability is uneven. Consider the following example. The original Uniform Random number range is 1 ~ 100. When I want to generate a new random number, the range is 1 ~ At the time of 30, I could have divided the numbers produced by the original random range into three groups. However, because 100 is not divisible by 30, the remaining four groups are not balanced ), [31, 60), [61, 90), [91,100). Therefore, 1 ~ is generated in the actual result ~ The probability of a random number of 10 is higher than that of a random number of 11 ~ 30 must be high. In this case, if the random number of 31bit is mapped to [0, n), if the number produced by next (31) is the last part, discard and retry. Therefore, the loop part of nextInt (n) is to solve this problem.
When n is an integer power of 2, n iron can be divisible by 2 ^ 31. At this time, you can directly map and perform a next (31) operation.
When n is not an integer power of 2, the inequality in the preceding example occurs. Therefore, special processing is required: When bits-val + (n-1) is <0, the result is regarded as an uneven part and the Retry is continued. So what does this sentence mean.
For 2 ^ 31/n = max... val, val is the remainder of 2 ^ 31 divided by n, and max is a multiple. 2 ^ 31-val = nMax is the maximum integer that can divide n not greater than 2 ^ 31. Then [nMax, 2 ^ 31) is the uneven part. If bits falls into this range, it can be determined as discarded and retried. Here we can obtain: nMax <2 ^ 31 <n (Max + 1)
When bits = next (31) is called, a random number of [0, 2 ^ 31) is obtained,
If bits <nMax, bits-val must be equal to a multiple of n (smaller than Max), and bits-val + n-1 must be smaller than nMax, so no Retry is required and the result is directly returned.
If bits> = nMax, then bits-val = nMax, then bits-val + n-1 = nMax + n-1 = n (Max + 1)-1> 2 ^ 31-1, equivalent to bits> = nMax, bits-val + n-1> = 2 ^ 31. Because the int type 2 ^ 31 overflows, 2 ^ 31 <0,
Therefore, while (bits-val + n-1 <0) is used to determine whether a Retry is required.
B. Why is the number of cycles of nextInt (n) less than 2 on average?
Appendix a describes the nextInt (n) principle. Retry after an uneven number is generated. But what is the number of retries. Consider the worst case, as stated in the javadoc of nextInt (n). When n = 2 ^ 30 + 1, the worst case is that the range of [nMax, 2 ^ 31) reaches the maximum. If n <2 ^ 30 + 1 is smaller, newMax can be found to make the range of [nNewMax, 2 ^ 31) smaller.
When n = 2 ^ 30 + 1, the uneven range [2 ^ 30 + 1, 2 ^ 31) and the Uniform range [0, 2 ^ 30) the number is basically the same, so there is a 50% chance to try again at this time. That is, in the worst case, only 50% of the probability is retried.
So in general, the average number of next (n) calls of nextInt (n) is less than 2, which is why it is faster than Math. random.
Author: UltraNi