Java中的弱僞隨機數Random

以下內容首發於我的個人博客網站:
http://riun.xyz/


隨機數:

Java中生成隨機數有三個影響因素:隨機種子seed隨機範圍bound產生隨機數的對象Random

隨機範圍bound不同,生成的隨機數肯定會有不同的可能,所以這裏不做討論。

下面討論的是seed和隨機對象Random對生成隨機數的影響。生成隨機數的對象又分爲弱僞隨機數和強僞隨機數,我們這裏討論弱僞隨機數。

實驗一:弱僞隨機數生成規律

	/**
     * 弱僞隨機數:相同的seed隨機出來的數是一摸一樣的,不同的seed隨機數來的數字不同(這是對於不同的Random產生的隨機數來說的,如果是同一個Random產生的,就不一定相同與否)
     * @param args
     * java.security.SecureRandom是強僞隨機數
     * java.util.Random 是弱僞隨機數
     */
    public static void main(String[] args) {
        //--------------------------------------------Random1----------------------------------------------------------------
        System.out.println("--------------------------------------------Random1:seed=100,不同Random對象,隨機結果相同----------------------------------------------------------------");
        ArrayList<Object> list1 = new ArrayList<>(100);
        ArrayList<Object> list2 = new ArrayList<>(100);
        //固定隨機種子seed 這裏兩個都是以100作爲seed
        Random t = new Random(100);
        Random t2 = new Random(100);

        //但是使用了不同Random對象生成隨機數
        for (int i = 0; i < 55; i++) {
            list1.add(t.nextInt(100));//bound限制產生100以內的隨機數
        }
        for (int i = 0; i < 55; i++) {
            list2.add(t2.nextInt(100));
        }
        //所以結果會相同
        System.out.println(list1);
        System.out.println(list2);
        //結論:(隨機範圍bound相同的情況下)使用不同Random對象,且使用相同的seed時,產生的隨機結果會完全一致。由此可知隨機數生成是一條線,每次重新起一個對象使用相同的seed生成隨機數時,完全是走的相同的路,可理解僞固定的函數,參數相同,再調用一遍結果也相同。


        //--------------------------------------------Random2----------------------------------------------------------------
        System.out.println("--------------------------------------------Random2:seed=100,相同Random對象,隨機結果不同----------------------------------------------------------------");
        ArrayList<Object> list3 = new ArrayList<>(100);
        ArrayList<Object> list4 = new ArrayList<>(100);
        //固定隨機種子seed
        Random t3 = new Random(100);

        //且使用相同Random對象生成隨機數
        for (int i = 0; i < 55; i++) {
            list3.add(t.nextInt(100));
        }
        for (int i = 0; i < 55; i++) {
            list4.add(t.nextInt(100));
        }
        //隨機結果不同
        System.out.println(list3);
        System.out.println(list4);
        //結論:由於使用同一個Random隨機對象,所以相當於一條線一直往後走,隨機結果不會完全重複(是否重複是看此隨機函數本身產生的結果是否會重複,即不受外界影響)。


        //--------------------------------------------Random3----------------------------------------------------------------
        System.out.println("--------------------------------------------Random3:時鐘作爲seed,相同Random對象,隨機結果不同。因爲相同Random隨機結果本就不同----------------------------------------------------------------");
        ArrayList<Object> list5 = new ArrayList<>(100);
        ArrayList<Object> list6 = new ArrayList<>(100);
        //這裏不寫就是以時鐘作爲seed
        Random t5 = new Random();

        for (int i = 0; i < 55; i++) {
            list5.add(t5.nextInt(100));
        }
        for (int i = 0; i < 55; i++) {
            list6.add(t5.nextInt(100));
        }
        //隨機結果不同
        System.out.println(list5);
        System.out.println(list6);
        //結論:和Random2一樣,只要是使用同一個隨機對象的,都是一條線往後走,但不能保證一定不會出現重複數據。


        //--------------------------------------------Random4----------------------------------------------------------------
        System.out.println("--------------------------------------------Random4:時鐘作爲seed,不同Random對象,隨機結果不同。因爲不同Random,他的隨機種子seed是隨着時間變化的,兩行代碼不是同一時間運行的,所以他們的seed值不同----------------------------------------------------------------");
        ArrayList<Object> list7 = new ArrayList<>(100);
        ArrayList<Object> list8 = new ArrayList<>(100);
        //這裏不寫就是以時鐘作爲seed
        Random t7 = new Random();
        Random t8 = new Random();

        for (int i = 0; i < 55; i++) {
            list7.add(t7.nextInt(100));
        }
        for (int i = 0; i < 55; i++) {
            list8.add(t8.nextInt(100));
        }
        //隨機結果不同
        System.out.println(list7);
        System.out.println(list8);
        //結論:因爲是使用時鐘作爲seed,在執行兩個代碼的時候時間是不同的,所以相當於seed不同


        //--------------------------------------------org.apache.commons.lang3.RandomUtils----------------------------------------------------------------
        //org.apache.commons.lang3.RandomUtils的隨機實現也是弱僞隨機數,因其內部是直接    private static final Random RANDOM = new Random(); 即使用時鐘作爲seed
        System.out.println("--------------------------------------------org.apache.commons.lang3.RandomUtils,永遠不同。因爲這個工具是靜態的,每次調用內部使用的是同一個Random,跟上面的Random3一樣----------------------------------------------------------------");
        ArrayList<Object> lista = new ArrayList<>(100);
        ArrayList<Object> listb = new ArrayList<>(100);

        for (int i = 0; i < 55; i++) {
            lista.add(org.apache.commons.lang3.RandomUtils.nextInt()); //return nextInt(0, Integer.MAX_VALUE); 隨機範圍bound是Integer.MAX_VALUE
        }
        for (int i = 0; i < 55; i++) {
            listb.add(org.apache.commons.lang3.RandomUtils.nextInt());
        }

        System.out.println(lista);
        System.out.println(listb);
    }

結果:

--------------------------------------------Random:seek=100,不同Random,隨機結果相同----------------------------------------------------------------
[15, 50, 74, 88, 91, 66, 36, 88, 23, 13, 22, 17, 56, 57, 52, 59, 80, 78, 73, 19, 53, 28, 65, 72, 67, 31, 48, 92, 0, 28, 74, 95, 16, 73, 44, 94, 87, 68, 6, 29, 55, 0, 39, 71, 31, 2, 85, 15, 62, 0, 58, 36, 19, 8, 59]
[15, 50, 74, 88, 91, 66, 36, 88, 23, 13, 22, 17, 56, 57, 52, 59, 80, 78, 73, 19, 53, 28, 65, 72, 67, 31, 48, 92, 0, 28, 74, 95, 16, 73, 44, 94, 87, 68, 6, 29, 55, 0, 39, 71, 31, 2, 85, 15, 62, 0, 58, 36, 19, 8, 59]
--------------------------------------------Random:seek=100,相同Random,隨機結果不同----------------------------------------------------------------
[45, 25, 52, 45, 48, 46, 57, 22, 54, 88, 34, 53, 77, 11, 71, 30, 56, 0, 51, 24, 63, 92, 32, 87, 83, 46, 26, 98, 93, 34, 71, 94, 12, 33, 38, 26, 28, 90, 53, 79, 39, 59, 26, 55, 52, 10, 91, 21, 59, 57, 62, 68, 16, 84, 24]
[4, 78, 10, 0, 8, 12, 34, 97, 86, 84, 39, 57, 45, 88, 52, 38, 69, 43, 30, 0, 8, 16, 49, 16, 35, 5, 41, 55, 83, 51, 38, 66, 98, 38, 99, 11, 97, 97, 92, 62, 59, 21, 55, 78, 9, 55, 53, 67, 90, 76, 43, 48, 79, 0, 11]
--------------------------------------------Random:時鐘作爲seek,相同Random,隨即結果不同。因爲相同Random隨機結果本就不同----------------------------------------------------------------
[37, 1, 43, 94, 43, 0, 56, 97, 38, 33, 15, 71, 97, 12, 38, 18, 70, 64, 23, 90, 48, 80, 33, 21, 77, 88, 59, 52, 22, 15, 71, 29, 71, 67, 96, 69, 43, 37, 41, 25, 95, 12, 57, 80, 43, 93, 3, 80, 9, 81, 46, 91, 83, 99, 15]
[48, 91, 14, 58, 59, 65, 78, 4, 84, 68, 62, 66, 64, 32, 8, 0, 97, 6, 44, 98, 58, 16, 65, 73, 68, 29, 13, 67, 60, 5, 1, 40, 49, 95, 35, 85, 87, 52, 27, 26, 90, 30, 14, 99, 1, 21, 97, 14, 82, 49, 83, 57, 74, 13, 45]
--------------------------------------------Random:時鐘作爲seek,不同Random,隨即結果不同。因爲不同Random,他的隨機種子seek是隨着時間變化的,兩行代碼不是同一時間運行的,所以他們的seek值不同----------------------------------------------------------------
[78, 23, 89, 52, 94, 23, 66, 52, 11, 55, 62, 16, 30, 89, 79, 95, 26, 90, 77, 2, 20, 37, 50, 55, 19, 43, 86, 19, 42, 30, 32, 53, 77, 79, 68, 26, 92, 97, 65, 85, 3, 40, 43, 89, 9, 50, 61, 53, 57, 33, 84, 52, 30, 6, 96]
[96, 38, 80, 78, 64, 2, 10, 70, 95, 98, 81, 56, 89, 69, 41, 87, 30, 84, 59, 51, 4, 2, 55, 61, 14, 97, 1, 12, 58, 51, 33, 29, 95, 21, 79, 76, 98, 74, 66, 50, 27, 9, 76, 11, 69, 12, 87, 57, 6, 41, 63, 56, 48, 7, 61]
--------------------------------------------org.apache.commons.lang3.RandomUtils,永遠不同。因爲這個工具是靜態的,每次調用內部使用的是同一個Random,跟上面的Random3一樣----------------------------------------------------------------
[1893665739, 257930553, 135278889, 830196142, 462095529, 1538972871, 131015981, 876091756, 348454191, 45715846, 1590689601, 1797587540, 65849987, 2128440538, 959475095, 1134108238, 1363057003, 1412258418, 1557545138, 1109175529, 599770516, 464633544, 1404869820, 1788244652, 144022399, 1700086728, 836544135, 1379793803, 1542852361, 496668040, 46777886, 552751733, 446238869, 2082027830, 373373191, 1093885962, 34720471, 423143440, 1961774617, 510476906, 1499575104, 54868107, 320881908, 1940394025, 1846277889, 618966935, 1271163680, 1042520158, 2072932030, 188265466, 1917235397, 118346203, 1410196177, 483024345, 1604620036]
[1450953590, 601229880, 1103625302, 1101117938, 590876550, 44715548, 1112429394, 944486447, 1811319914, 1416297471, 42513235, 1165040166, 2116891715, 652423297, 310865281, 1694673635, 1045538241, 391013582, 786580939, 2015401099, 2007978011, 870918311, 2142545191, 1014698621, 1284416536, 1263481612, 794521078, 1313729284, 18678859, 2099352452, 1840804997, 2117569205, 227427932, 1611820552, 1438498224, 1629502316, 426489728, 1973439378, 1774372257, 1425248477, 1074902538, 1512155453, 1372074166, 1622525145, 2082214427, 1625427993, 292710529, 1394629920, 1578272629, 983342989, 139052776, 1141707997, 1026146926, 221549673, 2111246701]

Process finished with exit code 0

實驗二:生成的隨機數全不同嗎

只是隨機數,因爲是隨機的,所以不能保證產生的數字完全不同,但是這個出現重複的原因是隨機算法導致的,不是人爲干擾或者使用錯誤導致的。即隨機數本來就是有可能重複的。

/**
     * 同一個Random生產的隨機數一定是不同的嗎? 不是
     * @param args
     */
    public static void main(String[] args) {
        HashSet<Object> set = new HashSet<>();
        Random random = new Random();
        for (int i = 0; i < 1000; i++) {
            set.add(random.nextInt(100));
        }
        System.out.println(set.size()); // 100
        //生成1000個隨機數,但是結果只有100個不同的,其他都是重複的

        HashSet<Object> set2 = new HashSet<>();
        Random random2 = new Random();
        for (int i = 0; i < 10000; i++) {
            set2.add(random2.nextInt(10000));
        }
        System.out.println(set2.size()); // 6284
        //生成10000個隨機數,即使bound取值爲10000,也不能保證所生成的隨機數全部不同

        HashSet<Object> set3 = new HashSet<>();
        Random random3 = new Random();
        for (int i = 0; i < 10000; i++) {
            set3.add(random3.nextInt(100000));
        }
        System.out.println(set3.size()); // 9513
        //即使擴大bound的範圍也不能保證所生成的隨機數全部不同
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章