(转) 随机数——随机函数——大数随机及等概率探讨

本文探讨了在特定范围内生成等概率随机数的方法,包括直接使用rand()函数、按位组合、丢弃法等,最终给出了一种适用于大范围随机数生成的有效方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要讨论大范围内随机数的产生办法,讨论在随机范围内的等概率问题。

一,要求

 1, 产生一个比较大的随机数。

  2, 产生的随机数在随机范围内等概率。
二,知识背景
  我们知道在C语言中有rand()函数可以提供随机数,rand()函数的范围为0到32727。我们假定认为rand()产生的随机数在0到32727范围内是等概率的。如果我们需要得到一个小范围内的随机数,比如0到55之间的随机数,那我们可以采用rand()%55。但是对于我们要得到一个更大范围内的随机数,rand()便满足不了我们的要求。
三,探讨过程
  1,两个rand相乘
  假设我们要产生一个10亿内的随机数,想到rand()可以产生0到32727,那么我们可以采用rand()*rand(),刚好能达到10亿的范围。
可是我们不难发现rand()*rand()会有问题,最大的问题是在规定范围内产生的随机数概率不等,比如一个大于32727的素数,就永远产生不了。而对于很多合数,出现的频率会非常高。
  2,按位组合
  首先我们找到上限数字的位数,然后对每一位产生一个0到9的随机数,并将产生的一系列0到9的数字组合起来。假设我们要产生一个10亿内的随机数,也就是我们需要产生0到999999999之间的随机数,我们首先求得999999999的位数是9位,然后我们产生9个数字,并将他们组合成一个9位数。比如:872345671,023478652。
  看上去没有什么问题,我们很好地解决了一个特别的随即范围,即10亿内。假如我们现在要产生一个60000内的随机数,也就是需要产生一个0到59999之间的数。如果我们按照上述办法,如果产生的数字大于59999,同时也是5位数,比如97863,我们该怎么办?
  3,求余法
  我们最先想到的是,如果产生的数字(98763)对范围(60000)求余,对一个数字求余,所得到的结果肯定是落在该数字的范围内。
  不难发现,我们这里同样有概率问题。对于40000到60000之间的数字,出现的概率为1/100000,对于0到40000之间的数字,出现的概率为2/100000,因此概率不等。
  4,逐位检验法
  我们将上限数字的逐位取出来,我们逐个产生0到该数字的随机数。对于产生0到59999只的随机数,我们先取第一位:5,我们产生一个0到5之间的随机数,第二位:9,我们产生0到9之间的随机数,最终组合出的5位则是0到59999之间。
  我们发现,这也只能解决特殊的数字范围。如果我们要产生一个0到51782之间的随数,这个方法就失效了。比如33216这个数字就产生不了,因为33216第二位3比范围(51782)第二位1大,永远产生不了。
  5,丢弃法
  同样地,我们首先依然采用组合法产生一个规定位数的数据,如果我们发现我们产生的数字在我们的范围之外,那我们选择丢弃该数据,继续产生随机数,一直到我们产生我们在范围内的随机数。不难证明,丢弃一个不正确的数字本身并不影响产生正确数字的概率。
  因此,采用按位组合法+丢弃法能满足我们的要求。
  这里只讨论了随机数的上线,对于随机数的下限同理。
四,源码实现

[cpp]  view plain copy
  1. //产生一个0到9的随机数    
  2. static __inline int min_rand()    
  3. {        
  4. return rand()%10;    
  5. }     
  6. /*************************************************************/    
  7. /*   函数作用:产生一个range范围内的随机数                   */    
  8. /*   参数1,range:取随机数的范围                            */    
  9. /*   返回:返回取得的数据                                    */    
  10. /*************************************************************/    
  11. int my_rand(const int range)    
  12. {        
  13. short bit = 0; //纪录位数        
  14. int tempt = range;        
  15. int rand_data = 0;        
  16.  while ( tempt > 0 )         
  17.  {            
  18.  bit++;            
  19.  tempt = tempt/10;        
  20.  }         
  21.  while (bit--)  
  22. {  
  23. rand_data = 10*rand_data + min_rand();  
  24. }  
  25. //组合随机数         
  26. if (rand_data >= range)  
  27. {           
  28. return my_rand(range);  
  29. }  
  30. //产生随机数不符合范围,继续         
  31. return rand_data;    
  32. }   

转载于:https://my.oschina.net/stlwtr/blog/78448

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值