使用Random的两个误区

.
随机数的问题(C++代码).
C/C++ code
    
    
for ( int i = 0 ;i < n; ++ i) { srand((unsigned)time( NULL )); int r = rand() % 100 ; cout << r << " , " ; }

这里很明显他是想输出一串小于100的随机的数列.可是运行结果输出的却是类似
97,97,97,97,....97,30,30,30,30,30,30,30,30,30,30,30,30,....,27,27,27,27,27,27,....
的序列.很明显这样完全看不出有任何的随机性.这是由于他对C的rand函数不理解导致
的错误用法.而这两天逛C#区我也同样看到了几个类似的错误用法(C和C#的rand从大体
的原理上差不多).想想自己初学的时候类似的错误犯得也不少.所以自己下去查了写资料
总结了在随机数使用上的一些错误的用法.希望能对初学者有所帮助.

先来说说随机数算法的实现.借用C数值算法里的一句话:利用计算机,这种人类所设计的
各种机器中最精确,最能做出确切判断的机器,来产生"随机数",这看上去有些自相矛盾.甚至在
概念上是讲不通的.任何程序必将产生完全可以预计的结果.因而不是真正的"随机数".

现在各种语言中的随机数产生函数所产生的"随机数",实际上被称之为"伪随机数".可以将
整个随机数函数看做这样一个表达式:

A = R(s)

其中R是随机函数,s是种子.A是一个数列.即对于任意一个种子s,经过R的计算后,总有一个确定
的数列A与之对应.而当在C#里调用var rnd = new Random (s)或在C里调用srand(s)实质上
所做工作之一就是设定这个种子.而rnd.Next();或rand()只不过是在A上取下一个元素而已.当然实
际的实现不可能事先计算一个数列A,所以rand()相当于由s计算出下一个数字s',然后将s'作为新
的种子赋值给s,最后将s'作为结果返回.

接下来就是两种常见的错误用法了:
C# code
    
    
for ( int i = 0 ;i < n; ++ i) { var rnd = new Random (s); // s是实先确定的一个数字 Console.Write ( " {0}, " ,rnd.Next()); }

这样使用随机数产生器只会产生一个固定的常数N.
因为每次都用同一个种子初始化了随机数产生器后调用了Next().
所取得的都是数列A上的第一个元素.而这个元素的值肯定是固定
的(当然N取什么值要看随机函数的实现而定).

而第二种情况就更常见了:
C# code
    
    
for ( int i = 0 ;i < n; ++ i) { var rnd = new Random (); // 用系统时间作为种子 Console.Write ( " {0}, " ,rnd.Next()); }


这样调用应该是希望通过时间的不同来达到随机的效果;但是得到的结果就和我那位朋友一样.会是形似
97,97,97,97,....97,30,30,30,30,30,30,30,30,30,30,30,30,....,27,27,27,27,27,27,....
的一串数列.这是因为Windows系统时钟的更新频率大概在10ms左右.而这个for循环的执行显然要快
得多.于是在一段执行时间内Environment.TickCount (Random的默认种子)或是C的time函数返回的
都是同一个值.从而导致rnd.Next在一段时间内返回一个常数.

所以正确的用法应该将随机数产生器的初始化移出循环:
C# code
    
    
var rnd = new Random (); // 用系统时间作为种子 for ( int i = 0 ;i < n; ++ i) { Console.Write ( " {0}, " ,rnd.Next()); }


就个人习惯来说.在一个经常用到随机数的程序中,我会在Main中就初始化一个全局的随机数产生器,在
之后要用到随机数的地方就直接调用Next,而不用每次都构造一个Random.




一般如果要输出的随机数不重复,都把生成好了的,放到一个列表中
Random rnd = new Random();
比如说输出1-100不重复的随机数
C# code
   
   
List < int > list = new List < int > (); for ( int i = 0 ;i < 100 ;i ++ ) { int value = rnd.Next( 1 , 101 ); while (list.Contains(value)) { value = rnd.Next( 1 , 101 ); } list.Add(value); }


然后输出list


转自:http://topic.csdn.net/u/20081227/13/5480C6A3-A3C5-4002-B961-6B0B08C907FF.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值