小议随机数

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/N。m可能是任意一张牌,因此对第一个位置满足了。对于第二个位置,由于已经有一张牌出局,只剩下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

时间: 2024-11-05 14:54:13

小议随机数的相关文章

shell系列生成随机数的方法

一: RANDOM echo $RANDOM RANDOM的随机数是有范围的1--32767,一般用它是可以被破解的 1.2  生成八位数的随机密码: echo $(($RANDOM+11111111)) 二:MD5sum 随机加密方法 生成的密码较长 取9位数密码: echo $RADDOM |md5sum|cut -c 2-9 三:通过openssl产生随机数 [[email protected] tmp]# openssl rand -base64 8 hInfIvtfOSk= [[ema

javaScript随机数取值方法

Math.random()方法返回0到1之间的一个随机数,不包括0和1 如若想取的一个范围的随机数可套用下面的公式: 一.X+开始数-1=结束数 二.Math.floor(Math.random()*X+开始数) 注:Math.floor()向下舍入,去掉小数点后数 例: //若想取的5到10之间的数,套用公式:①X+开始数-1=结束数//可得出X为6//②Math.floor(Math.random()*X+开始数)//for(var i=0;i<10;i++){ document.write

重复10个1~60顺序且不重复的随机数

$flag = 1; for ($i = 0; $i < 10; $i++) {     $data['mobile'] = $evaluate_mobile;     //随机时间     $second = rand($flag, 6 * ($i + 1));//重复10个1~60顺序且不重复的随机数     $flag = $second + 1;//加1是未免与上一结果重复     $data['second'] = $second;     $result[] = $data; }

r语言之生成随机序列,随机数生成函数及用法

(1)生成正态分布随机数: rnorm(n,mean,sd)     其中,n表示生成的随机数个数,mean表示正态分布均值,sd表示正态分布标准差 > rnorm(5,0,2)[1] -5.31147765 0.09634197 0.35276104 -1.94548466 0.54533883 (2)生成均匀分布随机数: runif(n,min,max)     其中,n表示生成的随机数个数,min表示均匀分布最小值,max表示均匀分布最大值 > runif(5,0,10)[1] 9.74

随机数和随机数种子(转)

在计算机中并没有一个真正的随机数发生器,但是可以做到使产生的数字重复率很低,这样看起来好象是真正的随机数,实现这一功能的程序叫伪随机数发生器. 有关如何产生随机数的理论有许多,如果要详细地讨论,需要厚厚的一本书的篇幅.不管用什么方法实现随机数发生器,都必须给它提供一个名为“种子”的初始值.而且这个值最好是随机的,或者至少这个值是伪随机的.“种子”的值通常是用快速计数寄存器或移位寄存器来生成的. 下面讲一讲在C语言里所提供的随机数发生器的用法.现在的C编译器都提供了一个基于ANSI标准的伪随机数发

六爻预测等各种预测术的本质探讨之随机数猜想

对于各类预测术,比如六爻术,源于周易八卦.大家对预测术的观点泾渭分明,要么很相信,要么很不屑.或者有些人认为信则有不信则无. 当然我本人是信奉现代科学的,不过预测术确实有不可思议的地方,对过去和未来的分析不是简单的一句"巧合,概率论"能说的过去的.现经过本人的一番分析,试图对各类预测术的本质来个大起底. 其实,预测术不神奇,更不是有什么鬼神之力.而且也不能说古人比现在人更聪明.预测术的外圈是遵循一定规律的一整套规则,这些规则是古代在不停的经验总结中逐步完善的.换句话说,只要你自己能遵循

SQL Server生成指定范围内的随机数

在开发中很多时候,我们都会遇到这种需要生成一个指定范围随机数的情况.而且在很多语言中比如Java.C#.SQl等,都会有一个函数生成一个类似于0.234273983423789的随机小数,而所有的随机数都是通过这个最基本的随机数(0.234273983423789)变化过来的. 下面我说一下生成指定范围随机数的思路,比如我要生成一个100-999范围内的随机数,我就要保证我写的生成随机数的表达式所生成的值,最大是999,最小是100.还有就是要明白一个数学里的小道理,0.99去乘一个数字所得的结

Spring Boot? 配置文件详解:自定义属性、随机数、多环境配置等

自定义属性与加载 我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义: application-dev.yml com.didispace.blog: name: 程序猿DD title: Spring Boot教程 desc: ${com.didispace.blog.name}正在努力写<${com.didispace.blog.title}> # 随机字符串 value: ${random.value} # 随机int number: ${

牛客网华为机试训练第3题 明明的随机数

今天花了一下午才把明明的随机数这个搞明白,期间和牛客网的编译器殊死搏斗.一直发现在本地编译器运行成功,但是在牛客上的老师不能通过.整的十分的恼火和焦躁.后来看到了相同的问题,才发现解决之道. 时间限制:1秒 空间限制:32768K 热度指数:222608 本题知识点: 数组 算法知识视频讲解 题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不