Java:Random函數及其種子的作用


偽隨機(preundorandom):通過算法產生的隨機數都是偽隨機!!

只有通過真實的隨機事件產生的隨機數才是真隨機!!比如,通過機器的硬件噪聲產生隨機數、通過大氣噪聲產生隨機數

 

Random生成的隨機數都是偽隨機數!!!

是由可確定的函數(常用線性同余),通過一個種子(常用時鍾),產生的偽隨機數。這意味着:如果知道了種子,或者已經產生的隨機數,都可能獲得接下來隨機數序列的信息(可預測性) 

Random類擁有兩個構造方法,用於實現隨機數生成器:

Random( ) 構造一個隨機數生成器
Random(long seed) 用種子seed構造一個隨機數生成器

 

 

 

一、無參構造方法(不設置種子)

雖然表面上看我們未設置種子,但Random構造方法里有一套自己的種子生成機制,源碼如下:

 1 /**
 2      * Creates a new random number generator. This constructor sets
 3      * the seed of the random number generator to a value very likely
 4      * to be distinct from any other invocation of this constructor.
 5      */
 6     public Random() {
 7         this(seedUniquifier() ^ System.nanoTime());
 8     }
 9 
10     private static long seedUniquifier() {
11         // L'Ecuyer, "Tables of Linear Congruential Generators of
12         // Different Sizes and Good Lattice Structure", 1999
13         for (;;) {
14             long current = seedUniquifier.get();
15             long next = current * 181783497276652981L;
16             if (seedUniquifier.compareAndSet(current, next))
17                 return next;
18         }
19     }
20 
21     private static final AtomicLong seedUniquifier
22         = new AtomicLong(8682522807148012L);

生成種子過程:(參考解密隨機數生成器(二)——從java源碼看線性同余算法

1、獲得一個長整形數作為“初始種子”(系統默認的是8682522807148012L)

2、不斷與一個變態的數——181783497276652981L相乘(天知道這些數是不是工程師隨便滾鍵盤滾出來的-.-)得到一個不能預測的值,直到 能把這個不能事先預期的值 賦給Random對象的靜態常量seedUniquifier 。因為多線程環境下賦值操作可能失敗,就for(;;)來保證一定要賦值成功

3、與系統隨機出來的nanotime值作異或運算,得到最終的種子

nanotime算是一個隨機性比較強的參數,用於描述代碼的執行時間。源碼中關於nanotime的描述(部分):

/**
     * Returns the current value of the running Java Virtual Machine's
     * high-resolution time source, in nanoseconds.
     *
     * <p>This method can only be used to measure elapsed time and is
     * not related to any other notion of system or wall-clock time.

 

二、有參構造方法(設置種子)

語法:Random ran = Random(long seed)

有參構造方法的源碼如下:

 1 /**
 2      * Creates a new random number generator using a single {@code long} seed.
 3      * The seed is the initial value of the internal state of the pseudorandom
 4      * number generator which is maintained by method {@link #next}.
 5      *
 6      * <p>The invocation {@code new Random(seed)} is equivalent to:
 7      *  <pre> {@code
 8      * Random rnd = new Random();
 9      * rnd.setSeed(seed);}</pre>
10      *
11      * @param seed the initial seed
12      * @see   #setSeed(long)
13      */
14     public Random(long seed) {
15         if (getClass() == Random.class)
16             this.seed = new AtomicLong(initialScramble(seed));
17         else {
18             // subclass might have overriden setSeed
19             this.seed = new AtomicLong();
20             setSeed(seed);
21         }
22     }
23 
24     private static long initialScramble(long seed) {
25         return (seed ^ multiplier) & mask;
26     }

其中的multiplier和mask都是定值:

1  private static final long multiplier = 0x5DEECE66DL;
2 
3  private static final long mask = (1L << 48) - 1;

三、代碼測試

分別采用有參和無參兩種方法,生成[0, 100)內的隨機整數,各生成五組,每組十個隨機數:

 1 import java.util.Random;
 2 
 3 public class RandomTest {
 4     public static void main(String[] args) {
 5         RandomTest rt = new RandomTest();
 6         rt.testRandom();
 7     }
 8 
 9     public void testRandom(){
10         System.out.println("Random不設置種子:");
11         for (int i = 0; i < 5; i++) {
12             Random random = new Random();
13             for (int j = 0; j < 10; j++) {
14                 System.out.print(" " + random.nextInt(100) + ", ");
15             }
16             System.out.println("");
17         }
18 
19         System.out.println("");
20 
21         System.out.println("Random設置種子:");
22         for (int i = 0; i < 5; i++) {
23             Random random = new Random();
24             random.setSeed(100);
25             for (int j = 0; j < 10; j++) {
26                 System.out.print(" " + random.nextInt(100) + ", ");
27             }
28             System.out.println("");
29         }
30     }
31 }

運行結果如下:

結論:

雖然二者都是偽隨機,但是,無參數構造方法(不設置種子)具有更強的隨機性,能夠滿足一般統計上的隨機數要求。使用有參的構造方法(設置種子)無論你生成多少次,每次生成的隨機序列都相同,名副其實的偽隨機!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM