JAVA认证培训辅导:随机整数的生成

随机

  使用Java 2 SDK基础类库产生随机数的方法很多。但是如果你跟不上这些类库的更新脚步,你有可能正在使用的是一种低效的随机数生成机制,更糟糕的是:你有可能得到的不是均匀分布的随机数。本文将向你展示一种较为可靠的随机数生成方法,同时与其他方法进行比较。

  自从JDK最初版本发布起,我们就可以使用java.util.Random类产生随机数了。在JDK1.2中,Random类有了一个名为nextInt()的方法:

  public int nextInt(int n)

  给定一个参数n,nextInt(n)将返回一个大于等于0小于n的随机数,即:0 <= nextInt(n) < n。

  你所要做的就是先声明一个Random的对象,在调用其nextInt(n)函数以返回随机值。

  这里有个示例,下面的代码段将生成很多随机数并输出它们的平均值:

  int count = 1000000;
  int range = Integer.MAX_VALUE / 3 * 2;
  double sum = 0;
  Random rand = new Random();
  for (int i=0; i 
  sum += rand.nextInt(range);
  }
  System.out.println(sum/count);

  执行了1000000次循环之后,得到的平均值基本上就处于随机数范围的中点(midpoint)。

  到目前为止,事情还并不复杂,但是我们会问为什么要使用nextInt(n)?考虑一下的随机数生成方法:

  (1)使用老的方法nextInt(),没有制定数值范围

  (2)用Math.abs()静态函数得到(1)中产生值的绝对值

  (3)对(2)的结果进行取模运算(%),得到期望范围类的值

  我们说nextInt(n)要比上述方法更好,为什么呢?参考以下的代码段:

  sum = 0;
  for (int i=0; i 
  sum += Math.abs(rand.nextInt()) % range;
  }
  System.out.println(sum/count);

  不难发现,每次循环都多出了几步运算。事实上,这种随机数生成的方法存在着以下三个问题:

  首先,nextInt()返回的值是趋于均匀分布在Integer.MIN_VALUE 和 Integer.MAX_VALUE之间的。如果你取Integer.MIN_VALUE的绝对值,得到的仍然不是一个正数。事实上,Math.abs(Integer.MIN_VALUE)等于Integer.MIN_VALUE。因此,存在着这样一种情况(虽然很少见):rand.nextInt()=Integer.MIN_VALUE,经过取绝对值Math.abs(rand.nextInt())之后,得到是一个负数。这种几率为 1/(2^31),在我们的测试中不太可能发生——循环次数只有1000000次。

  其次,当你对nextInt()取模时,你使结果的随机性大打折扣。随机数中较小的值出现的几率更大一些。这就是众所周知的伪随机数生成,因此我们不是用取模的方法。

  最后,也可能是最糟糕的:随机数不是均匀分布。如果你执行了上述的两段代码,第一段代码的结果将会大于715,000,000,考虑到数值范围的中点(midpoint)是715,827,882,所以这是一个可以接受的结果。然而,你会吃惊的发现第二段代码得到的平均值肯定不会超过600,000,000。

  为何第二段代码的结果会如此的偏差?纠其本质,问题出在数值分布的不均匀。当你进行取模运算时,你将过大的数转换成了较小的。这使得较小的数更容易产生。

  使用nextInt(range)将会解决上述的三个问题。

  还有一种随机数生成方法——使用Math.random()。这个方法的效果如何?

  sum = 0;
  for (int i=0; i 
  sum += (int)(Math.random() * range);
  }
  System.out.println(sum/count);

  很好,使用random()不会碰到nextInt()的麻烦。你不会得到负数返回值,没有使用取模运算,值分布也是均匀的。还有什么问题吗?你有没有考虑到Math.random()使用了浮点运算,而nextInt()和nextInt(range)只有整数操作?Math.random()可能会慢上四倍。再加上从浮点到整数的类型转换,整个运算将会更慢。

  好了,经过一番比较,我们发现使用nextInt(range)生成随机数更为有效,因为它避免了其他方法的种种弊端。

  最后再给出一段代码,通过测试可以比较本文提到的几种随机数生成方法。

  import java.util.*;
  import java.text.*;
  public class RandomTest {
  public static void main(String args[]) {
  NumberFormat nf = NumberFormat.getInstance();
  int count = 1000000;
  int range = Integer.MAX_VALUE / 3 * 2;
  System.out.println("Midpoint: " + nf.format(range/2));
  double sum = 0;
  Random rand = new Random();
  for (int i=0; i 
  sum += rand.nextInt(range);
  }
  System.out.println("Good : " + nf.format(sum/count));
  sum = 0;
  for (int i=0; i 
  sum += Math.abs(rand.nextInt()) % range;
  }
  System.out.println("Bad : " + nf.format(sum/count));
  sum = 0;
  for (int i=0; i 
  sum += (int)(Math.random() * range);
  }
  System.out.println("Longer : " + nf.format(sum/count));
  }
  }

时间: 2024-11-01 06:31:09

JAVA认证培训辅导:随机整数的生成的相关文章

JAVA基础培训(10),方法的Overload介绍

今天在项目里做事,中午休息时间,补上这个教程吧.这次我们看看Overload 的内容 . 测试代码 package lession10; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * 老紫竹JAVA基础培训(10),方法的Overload介绍.<br> * 匹配方式为最特殊匹配,或者叫最准确匹配<br> * 如果发现多个都有相同的匹配度,则编译报错. * *

JAVA基础培训(9),控制台键盘输入(System.in)

从键盘输入是一个很重要的功能,这里给出了个人推荐的方式,用Scanner读取输入数 据 package lession9; import java.io.InputStream; import java.util.Scanner; /** * 老紫竹JAVA基础培训(9),控制台键盘输入(System.in). * * @author 老紫竹 JAVA世纪网(java2000.net) * */ public class Lession9 { public static void main(St

JAVA基础培训(7),构造器的使用

这里主要看类的构造器的情况,默认的,无参数的,有参数的,有不同参数类型的, 有多个参数的等各种情况. package lession7; /** * 老紫竹JAVA基础培训(7),构造器的使用.<br> * * @author 老紫竹 JAVA世纪网(java2000.net) * */ public class Lession7 { public static void main(String[] args) { new class1(); // 使用了系统自动提供的无参数构造器 new c

JAVA基础培训(5),IF语句的使用

这一小节,我们看看if语句的用法,最主要是相等的判断.对于数字还有大于小于的 判断. package lession5; /** * 老紫竹JAVA基础培训(5),IF语句的使用.<br> * * @author 老紫竹 JAVA世纪网(java2000.net) * */ public class Lession5 { public static void main(String[] args) { // ---------------------------------------- //

Java Web开发之图形验证码的生成与使用方法_JSP编程

本文实例讲述了Java Web开发之图形验证码的生成与使用方法.分享给大家供大家参考.具体如下: 图形验证码的主要目的是为了增强的安全性,增加用户通过遍历所有可能性来破解密码的难度. 图形验证码的使用包括如下3部分: ① 图形验证码的生成: ② 在页面中的使用: ③ 验证: 1.图形验证码的生成 假设在Servlet生成图形验证码,在JavaBean或者JSP中生成的基本过程是相同的.设计如下过程: ① 设置响应的文档类型: ② 生成随机码: ③ 把随机码保存到session中: ④ 生成图片:

关于java认证考试

问题描述 现在Oracle的java认证考试都是考哪门啊?网上查了下,以前好多人考的是1Z0-851JavaSE6ProgrammerCertifiedProfessional但SE6太老了,官网推荐的是考1Z0-803JavaSE7ProgrammerI,然后是1Z0804那我这种初学者该报考那门啊? 解决方案 本帖最后由 caprica2010 于 2014-10-28 14:44:58 编辑解决方案二:这里有人考过没?解决方案三:我都忘记了Java原来还有认证考试啊解决方案四:考这个有什么

java认证:java报表扩展功能

问题描述 java认证:java报表扩展功能.报表工具的做基础报表功能已经不能满足于使用者多元化的统计分析需求,在应用中需要有相关的扩展功能模块给以实现,如灵活的通用查询分析功能,快捷的即时报表,高级的OLAP分析实现,java报表管理与调度等,都是提高使用者操作效率不错的扩展功能选择.但具体这些java报表的扩展功能要求是什么,应该有什么样的作用.下面本文简单介绍一下.通用查询:通用查询以查询结果包含的字段为对象,使用者可以灵活地任意组合自行定义复杂的查询条件,进行数据的过滤与分析,并对查询条

Java对文件的随机读写以及压缩处理操作_java

Java中文件的随机读写 Java.io 包提供了 RandomAccessFile 类用于随机文件的创建和访问.使用这个类,可以跳转到文件的任意位置读写数据.程序可以在随机文件中插入数据,而不会破坏该文件的其他数据.此外,程序也可以更新或删除先前存储的数据,而不用重写整个文件. RandomAccessFile类是Object类的直接子类,包含两个主要的构造方法用来创 建RandomAccessFile 的对象,如表所示. 需要注意的是,mode 表示所创建的随机读写文件的操作状态,其取值包括

Java认证宝典v1.0之SCJD篇

Java认证宝典v1.0之SCJD篇Java认证宝典v1.0之SCJD篇(本文为www.java365.com原创,版权所有,转载请注明出处) 在J2EE尚未得到规模应用以前,SCJD是java认证中的高级认证.即便现在有了SCWCD.SCJA等认证,SCJD依然有其独特的魅力. 一.考试目标 Programming Assignment Objectives Write an application program using Java technology. The application