2015070102 - EffactiveJava笔记 - 第47条 了解和使用类库(1)

来源:互联网 发布:网络语713是什么意思 编辑:程序博客网 时间:2024/06/08 07:23

    20150701 星期三 北京

    如果希望产生位于0到某个上届之间的随机整数,如何处理?

       privatestatic final Random rnd = new Random();
       staticint random (int n) {
          returnMath.abs(rnd.nextInt()) % n;
       }

    存在的错误不容易发觉,可以运行,但是运行的原理导致问题.

    1.如果n是比较小的2的乘方,经过比较短的周期,随机数序列会重复;

    2.如果n不是2的乘方,某些数会比其他数字出现更加频繁.如果n比较大,缺点更加明显.

    可以通过下面的程序体现出来

       private static final Random rnd = new Random();

       static int random (int n) {

              returnMath.abs(rnd.nextInt()) % n;

       }

       public static void main(String[] args) {

              intn = 2 * (Integer.MAX_VALUE / 3);

              intlow = 0;

              for(int i = 0; i < 1000000; i++) {

                     if(random(n)< n/2) {

                            low++;

                     }

              }

              System.err.println(low);//666575

       }

    代码会产生1百万个指定范围的随机数,并打印出来多少数字落在取值范围的前半部分.

    预期的结果是打印的数字接近50万,实际结果是666575,由random方法产生的数字2/3落在随机数取值的前半部分.

 

    3.极少情况,结果是灾难性的,返回落在指定范围之外的数字.因为方法调用Math.abs(),将rnd.nextInt()的返回值取绝对值int,如果nextInt()方法返回Integer.MIN_VALUE,那么Math.abs()会返回Integer.MIN_VALUE.确实如此.

    System.err.println(Math.abs(Integer.MIN_VALUE));//-2147483648

    如果n不是2的次方,那么取模运算返回的是负数,并且很难复现.

    System.err.println(Math.abs(Integer.MIN_VALUE) %3); //-2

 

    如何修正这3个问题呢?

    有必要了解伪随机数,数论,2的求补运算.但是现有API,Random.nextInt(int)解决问题.

    通过使用标准类库,可以充分发挥标准类库专家的知识,以及在你之前其他人的使用经验.

0 0
原创粉丝点击