码迷,mamicode.com
首页 > 其他好文 > 详细

小议随机数

时间:2015-04-26 18:26:20      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:

C语言中可以使用rand()函数来生成一个从0到RAND_MAX的uniform分布。而rand()函数一般是用线性同余法来实现伪随机

线性同余法

线性同余方法LCG)是个产生伪随机数的方法。

它是根据递归公式:

其中是产生器设定的常数。

LCG的周期最大为,但大部分情况都会少于M。要令LCG达到最大周期,应符合以下条件:

1.   互质

2.   的所有质因数都能整除

3.   4倍数也是;

4.   都比小;

5.   是正整数。

C语言中rand()就是利用这个公式,由于这个公式每次产生的数值是有规律的,因此需要一个不同的随机值。鉴于此,srand()根据当前时间可以给定一个起始值,也就是种子,也就是N0。

我的重点不在于探讨rand()产生的历史和方法,而是使用这个rand来看看一些随机函数怎么实现。

0到1的uniform分布

//generate a random number in the range of[0,1]
double uniform_zero_to_one(){
    return (double)rand()/RAND_MAX;
}


 

 

任意实数区间的uniform分布

//generate a random real number in [start,end]
double uniform_real(double start,double end){
    double rate=(double)rand()/RAND_MAX;
    return start+(end-start)*rate;
}


 

任意整数区间的uniform分布

//generate a random integer number in [start,end)
int uniform_integer(int start,int end){
    int base=rand();
    if(base==RAND_MAX)
        return uniform_integer(start,end);
    int range=end-start;
    int remainder=RAND_MAX%range;
    int bucket=RAND_MAX/range;
    if(base<RAND_MAX-remainder)
        return start+base/bucket;
    else
        return uniform_integer(start,end);
 
 
}


 

32bits的随机数

//generate a random 32 bits integer number 
int rand32(){
    return ((rand()<<16)+(rand()<<1)+rand()%2);
}


 

 

有了32bits的随机数生成方法,就可以构造32bits范围内的随机整数区间了,方法和之前16bits的情况一样。

32bits范围内的随机整数区间

//generate a random 32bits integer number in [start,end)
 int uniform_integer_32(int start,int end){
     int base=rand32();
    if(base==RAND32_MAX)
        return uniform_integer_32(start,end);
    int range=end-start;
    int remainder=RAND32_MAX%range;
    int bucket=RAND32_MAX/range;
    if(base<RAND32_MAX-remainder)
        return start+base/bucket;
    else
        return uniform_integer_32(start,end);
}


 

面试常见问题

此外,在实际的情况中,常常出现一些变形问题。

1、  已知随机数函数rand5(),可以均匀随机生成1~5,编写随机函数rand7(),可以随机生成1~7,并且保持均匀性。

解答:

利用rand5()等概率随机生成1~25,然后去掉22~25,最后将结果%7+1,就等到等概率分布的1~7。

</pre><pre>
这很需要注意的是对于randN(1,N),rst = (randN - 1)*N + randN。这可以用数学归纳法轻松证明。对于randN(0,N),rst = randN*(N+1) + randN+1。
int rand5();

	int rand7(){
   	int rst = 0;
   	do{
      		rst = (rand5()-1)*5 + rand5();
   	}while(rst > 21);
   	return rst %7 + 1;
}


2、  已知随机数函数rand1(),p的概率等于0,(1-p)的概率等于1,编写随机函数rand01(),可以等概率生成0和1。

解答:

这有个巧妙方法。具体见代码吧。

 

Int rand01()
{
Int r1 = rand1();
Int r2 = rand1();
If(r1 && !r2) return 0;
If(!r1 && r2) return 1;
Else return rand01();
}

 

哈哈,上面0和1就这样等概率产生。利用产生的01等概率随机函数,可以实现更多的随机函数。

 

 

3、  洗牌算法。有一副牌假设有N张,请设计一个随机洗牌算法

解答:这个题很经典也很简单。但他的思想代表了很多随机函数的应用。所谓随机,即在每一个位置,任何一张牌出现概率一样。由于有N张牌,显然在每个位置每张出现的概率都为1/N。对于第1个位置,随机取一张m,概率为1/Nm可能是任意一张牌,因此对第一个位置满足了。对于第二个位置,由于已经有一张牌出局,只剩下N-1张牌,随机选一张,概率为1/N-1。似乎不大对??其实是由于忽视了取第一张牌时的概率。对于第二个位置,可选择的牌第此都没取到,概率为(N-1)/N.因此对于第二个位置,概率为(N-1)/N * 1/(N-1) = 1/N。得证。

 

代码如下:

void suffle(int ar[], int n)
{
while(n>1){
        swap(ar[n-1],ar[rand()%n]);
        n--;
}
}


 

4、  快速生成10亿个不重复的18位随机数的算法(从n个数中生成m个不重复的随机数)

 

解答:这个题很和洗牌算法异曲同工。相当于随机洗牌后,取出前m个牌。代码就不给了。



补充

C++ 11中终于有了随机函数。见链接:http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution


小议随机数

标签:

原文地址:http://blog.csdn.net/jr19911118730/article/details/45289275

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!