a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 204|回复: 1

[专业语言] JAVA认证考试专业语言基础知识12

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
使用java 2 SDK基础类库产生随机数的方法很多。但是如果你跟不上这些类库的更新脚步,你有可能正在使用的是一种低效的随机数生成机制,更糟糕的是:你有可能得到的不是均匀分布的随机数。本文将向你展示一种较为可靠的随机数生成方法,同时与其他方法进行比较。
; |" r+ a% A! Y1 `* s  自从JDK最初版本发布起,我们就可以使用java.util.Random类产生随机数了。在JDK1.2中,Random类有了一个名为nextInt()的方法:" H0 d% i3 W$ x+ L5 k. \
  public int nextInt(int n)
: D( X4 c7 _5 s( [) L, `
  ~, l3 h. a, W* ^4 R" d6 X  给定一个参数n,nextInt(n)将返回一个大于等于0小于n的随机数,即:0
回复

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:45 | 显示全部楼层

JAVA认证考试专业语言基础知识12

  不难发现,每次循环都多出了几步运算。事实上,这种随机数生成的方法存在着以下三个问题:</p>  首先,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次。- s8 C( {9 `- N- n3 v- H( _
  其次,当你对nextInt()取模时,你使结果的随机性大打折扣。随机数中较小的值出现的几率更大一些。这就是众所周知的伪随机数生成,因此我们不是用取模的方法。, G7 ]2 N; c3 |7 Q/ D% [- X' ]" s
  最后,也可能是最糟糕的:随机数不是均匀分布。如果你执行了上述的两段代码,第一段代码的结果将会大于715,000,000,考虑到数值范围的中点(midpoint)是715,827,882,所以这是一个可以接受的结果。然而,你会吃惊的发现第二段代码得到的平均值肯定不会超过600,000,000。
, c$ E4 P& K6 R" h; v  为何第二段代码的结果会如此的偏差?纠其本质,问题出在数值分布的不均匀。当你进行取模运算时,你将过大的数转换成了较小的。这使得较小的数更容易产生。4 M2 \% Y% }/ t3 N: {* C" b. C$ M
  使用nextInt(range)将会解决上述的三个问题。/ i3 [+ c, d- S6 j$ G) B, [
  还有一种随机数生成方法——使用Math.random()。这个方法的效果如何?
0 \- n, R5 U& M& W- e& ^4 M/ T以下是引用片段:
0 `0 E4 u) s7 e  sum = 0; - _0 ^( n" L0 C/ ~
  for (int i=0; i  9 a+ I8 }3 T% f1 }
  sum += (int)(Math.random() * range);
) ^+ y! m5 V! ^$ Z  }
3 q. U; A: ^" `* t  System.out.println(sum/count);
, T( j7 f: U. n( w* o9 T
4 h* ]! M5 X/ K6 m) _" w) P  很好,使用random()不会碰到nextInt()的麻烦。你不会得到负数返回值,没有使用取模运算,值分布也是均匀的。还有什么问题吗?你有没有考虑到Math.random()使用了浮点运算,而nextInt()和nextInt(range)只有整数操作?Math.random()可能会慢上四倍。再加上从浮点到整数的类型转换,整个运算将会更慢。
2 D+ `. r; b1 B; ^2 `) ^7 r6 _  好了,经过一番比较,我们发现使用nextInt(range)生成随机数更为有效,因为它避免了其他方法的种种弊端。0 j0 @5 r& g& d( d1 `
  最后再给出一段代码,通过测试可以比较本文提到的几种随机数生成方法。
$ ~# X* i9 J; U- k9 u% u以下是引用片段:
1 t4 C4 C  ]. F; `. q  import java.util.*;
4 F: X+ @& x+ X6 p0 D1 M- ~  import java.text.*;
  c& D) r2 Z' D) d1 D8 z3 L! D  public class RandomTest {
) R( U, g( R  G  public static void main(String args[]) {
/ `+ j7 H- M" Q( @1 b7 K  o% l  NumberFormat nf = NumberFormat.getInstance(); ( J, W" Y  c+ ^& V1 W! t5 Z
  int count = 1000000;
. b; ]1 [8 x2 o2 `  int range = Integer.MAX_VALUE / 3 * 2;
/ Z9 r4 e. j& h* I( q( i  System.out.println("Midpoint: " + nf.format(range/2));
' R6 }% M6 V; J( H. G  double sum = 0;
# V5 r' m. F2 |5 v  Random rand = new Random();
5 m3 W% s3 t& [  w2 e6 X: s  for (int i=0; i  , v. ^. Q1 a0 V8 J$ e
  sum += rand.nextInt(range);
4 C2 n$ t( p3 r; {. N8 z6 _  } - k2 F6 _1 E5 J) A3 M
  System.out.println("Good : " + nf.format(sum/count));
- l2 i& j& ~( `0 ]7 |2 x$ C- X  sum = 0; & }9 |& m5 D6 H+ M( ?
  for (int i=0; i  ! i3 v5 {+ q5 s% _/ q4 K7 `* k5 X
  sum += Math.abs(rand.nextInt()) % range;
4 }: v- B2 ?. Z8 n  } 1 s7 \# J7 }5 Q( z% z0 M+ [
  System.out.println("Bad : " + nf.format(sum/count));
" z' a$ E  v/ z# y+ I  sum = 0;
3 c, C7 W3 m# i( x  n  k  for (int i=0; i  " V# R' d- x( h$ s  }
  sum += (int)(Math.random() * range);
$ \) C& g) `* |6 R7 A) t( D% ?. m  }
* O- ~# l& Y- U/ ]+ u% s# ]. J# _  System.out.println("Longer : " + nf.format(sum/count)); * q. I, b. m8 ~9 O5 _: X
  }
  ^1 j  V) @8 Z  }2 J  A) d1 ?1 m  }
& G9 l4 i. C3 B8 y* Q# ?-
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-9-21 08:50 , Processed in 0.251153 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表