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的范围也不能保证所生成的随机数全部不同
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章