C语言/C++中怎样产生随机数
C语言/C++怎样产生随机数:这里要用到的是rand()函数, srand()函数,C语言/C++里没有自带的random(int number)函数。
(1)
例如:
#include<stdio.h>
#include<stdlib.h>
void main()
{
for(int i=0;i<10;i+)
printf("%d\n",rand()); //printf("%d\n",rand()%100);
}//这里貌似有点小问题,若用rand()%n(n表示范围),也是可以产生一定范围的随机数的。
(2)
例如:随机生成10个0~100的数(主题代码):
#define random(x) (rand()%x)
for(int x=0;x<10;x++)
printf("%d\n",random(100)); //范围,0~100。
---------------------
(3)但是上面两个例子所生成的随机数都只能是一次性的,如果你第二次运行的时候输出结果仍和第一次一样。这与srand()函数有关。srand()用来设置rand()产生随机数时的随机数种子。
在调用rand()函数产生随机数前,必须先利用srand()设好随机数种子(seed), 如果未设随机数种子, rand()在调用时会自动设随机数种子为1。
上面的两个例子就是因为没有设置随机数种子,每次随机数种子都自动设成相同值1 ,进而导致rand()所产生的随机数值都一样。
srand()函数定义 : void srand (unsigned int seed);
通常可以利用geypid()或time(0)的返回值来当做seed
如果你用time(0)的话,要加入头文件#include<time.h>
例如:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define random(x) (rand()%x)//此x表示。。
intmain()
{
srand((int)time(0));
for(int x=0;x<10;x++)
printf("%d\n",random(100)); //产生0~100之间的数。
return 0;
}
这样两次运行的结果就会不一样了!!
------------------------------------------------------------------
rand()通常的使用方法是这样的:
rand()不需要参数,它会返回一个从0到最大随机数的任意整数,最大随机数的大小通常是固定的一个大整数。
这样,如果你要产生0~10的10个整数,可以表达为:
int N = rand() % 11;
这样,N的值就是一个0~10的随机数,如果要产生1~10,则是这样:
int N = 1 + rand() % 11;
总结来说,可以表示为:
a + rand() % n
其中的a是起始值,n是整数的范围。
//此处,需用一个for循环控制要产生随机数的个数。
--------
ok。我自己写小段代码测试下(主体代码):
//不过,每次产生的随机数,都是相同的。莫急,以下有解决办法。
---------------------------------------------
若要0~1的小数,则可以先取得0~10的整数,然后均除以10即可得到随机到十分位的10个随机小数,若要得到随机到百分位的随机小数,则需要先得到0~100的10个整数,然后均除以100,其它情况依此类推。
----
如 in a=rand()%10;
-----------
通常rand()产生的随机数在每次运行的时候都是与上一次相同的,这是有意这样设计的,是为了便于程序的调试。若要产生每次不同的随机数,可以使用srand( seed )函数进行随机化,随着seed的不同,就能够产生不同的随机数。
----------
如:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
}
//这样,就能每次都产生出不同的随机数了。
如大家所说,还可以包含time.h头文件,然后使用srand( time(0))来使用当前时间使随机数发生器随机化,这样就可以保证每两次运行时可以得到不同的随机数序列(只要两次运行的间隔超过1秒)。
待续中。。。
-------------------------------------------------------------
随机数产生原理及应用
原创作者:EmilMatthew
摘要 :
本文简述了随机数的产生原理,并用 C 语言实现了迭代取中法,乘同余法等随机数产生方法,同时,还给出了在符合某种概率分布的随机变量的产生方法。
关键词 : 伪随机数产生,概率分布 , 正态随机数 , 泊松随机数 , 高斯随机数
1 前言 :
在用计算机编制程序时,经常需要用到随机数,尤其在仿真等领域,更对随机数的产生提出了较高的要求,仅仅使用 C 语言类库中的随机函数已难以胜任相应的工作。
用投色子计数的方法产生真正的随机数 , 但电脑若也这样做 , 将会占用大量内存 ; 用噪声发生器或放射性物质也可产生真正的随机数 , 但不可重复 .
而用数学方法产生最适合计算机 , 这就是周期有限 , 易重复的 ” 伪随机数 ”
注 : 这里生成的随机数所处的分布为 0-1 区间上的均匀分布。不是 0-1 区间怎么办 ? 除以 (high-low), 再加上 low 不就行了 . 我们需要的随机数序列应具有非退化性,周期长,相关系数小等优点。
2.1 迭代取中法:
这里在迭代取中法中介绍平方取中法 , 其迭代式如下 :
其中, Xn+1 是迭代算子,而 Rn+1 则是每次需要产生的随机数
第一个式子表示的是将 Xn 平方后右移 s 位,并截右端的 2s 位。
而第二个式子则是将截尾后的数字再压缩 2s 倍,显然 :0=<Rn+1<=1.
迭代取中法有一个不良的性就是它比较容易退化成 0.
实现 : 网上一大把 , 略 .
乘同余法的迭代式如下 :
各参数意义及各步的作用可参 2.1
当然,这里的参数的选取至关重要 .
经过前人检验的两组性能较好的素数取模乘同余法迭代式的系数为 :
1 )
2 )
实现 : 请注意,这里一定要用到 double long, 否则计算 2^32 会溢出
2.3 混合同余法: C++ 中的 rand() 就是这么实现的 , 伪随机 , 故使用前一定要加 srand() 来随机取种 , 这样每次实验结果才不会相同 .
混合同余法是加同余法和乘同余法的混合形式 , 其迭代式如下 :
Xn+1=( Lamda*Xn+C )%M
Rn+1=Xn/M
Lamda=2^b+1,b 取 q/2 附近的数
X0 为任意非负整数
它的一个致命的弱点,那就是随机数的生成在某一周期内成线性增长的趋势,显然,在大多数场合,这种极富“规律”型的随机数是不应当使用的。
实现 :
1 double
10
11 }
3连续型随机变量的生成:
Xi=G(Ri)
其中 ,Ri 为一个 0-1 区间内的均匀分布的随机变量 .
F(X) 较简单时,求解较易,当 F(X) 较复杂时,需要用到较为复杂的变换技巧。
可能你没明白 , 看 3.1.1 的例子就一定会明白 .
3.1.1 平均分布 :
已知随机变量密度函数为 :
3.1.2 指数分布 :
指数分布的分布函数为 :
x<0 时 ,F(x)=0
利用反函数法,可以求得 :
3.2 正态分布随机变量的生成 :
正态分布在概率统计的理论及应用中占有重要地位,因此,能产生符合正态分布的随机变量就在模拟一类的工作中占有相当重要的地位。
下面介绍两种方法。
3.2.1
1) 产生位于 0-1 区间上的两个随机数 r1 和 r2.
2) 计算 u=2*r1-1,v=2*r2-1 及 w=u^2+v^2
3) 若 w>1 ,则返回 1)
4)
如果为 (miu,sigma^2) 正态分布 , 则按上述方法产生 x 后, x’=miu+sigma*x
由于采用基于乘同余法生成的 0-1 上的随机数的正态分布随机数始终无法能过正态分布总体均值的假设检验。而采用 C 语言的库函数中的随机数生成函数 rand() 来产生 0-1 上的随机数,效果较为理想。
3.2.2 利用中心极限定理生成符合正态分布的随机量:
根据独立同分布的中心极限定理,有 :
实现 :
1
10
11
12
13
14
10
4 离散型随机变量的生成 :
基本的思想是这样的:
1)在泊松分布中,求出 X 取何值时, p(X=k) 取最大值时,设为 Pxmax.
2) 通过迭代,不断生成 0-1 区间上的随机数,当随机数 <Pxmax 时,则终止迭代,否则重复 (2)
3) 记录迭代过程的次数,即为所需要得到的符何泊松分布的随机量。
显然,这种方法较为粗糙,在试验的过程中发现:生成的的随机量只能算是近似的服从泊松分布,所以,更为有效的算法还有待尝试。
实现 : 采用
10
11
12
13
14
15
16
17
为防止lamda过大而溢出,故应该自己来写一个浮点类,我不懂,摘抄的.
7
4.2符合二项分布的随机变量的生成:
符合二项分布的随机变量产生类似上限拦截法,不过效果要好许多,这是由二项分布的特点决定的。
具体方法如下:
设二项分布B(p,n),其中,p为每个单独事件发生的概率:
关键算法:
i=0;reTimes=0
while(i<n)
{
}
显然,直观的看来,这种算法将每个独立的事件当作一个0-1分布来做,生成的0-1区间上的随机数,若小于1-p则不发生,否则认为发生,这样的生成方式较为合理。实验结果也验证了其合理性。
4.3高斯分布随机数:贴一个最经典的程序,看程序大概就知道高斯分布函数的反函数了.
#include <stdlib.h>
#include <math.h>
double gaussrand()
{
}
------------------------------------------------
关于伪随机浮点数:
用rand() / double(RAND_MAX)可以取得0~1之间的浮点数(注意,不同于整型时候的公式,是除以,不是求模),举例:
double ran_numf=0.0;
srand((unsigned)time(0));
for(int i=0;i<10;i++){
ran_numf = rand() / (double)(RAND_MAX);
cout<<ran_numf<<" ";
}
运行结果为:0.716636,0.457725,…等10个0~1之间的浮点数,每次结果都不同。
如果想取更大范围的随机浮点数,比如1~10,可以将
rand() /(double)(RAND_MAX) 改为 rand() /(double)(RAND_MAX/10)
运行结果为:7.19362,6.45775,…等10个1~10之间的浮点数,每次结果都不同。
至于100,1000的情况,如此类推。
以上不是伪随机浮点数最好的实现方法,不过可以将就着用用…
---------------------------------
以下是线性同余法生成伪随机数的伪代码:
Random(n,m,seed,a,b)
{
r0 = seed;
for (i = 1;i<=n;i++)
ri = (a*ri-1 + b) mod m
}
其中种子参数seed可以任意选择,常常将它设为计算机当前的日期或者时间;m是一个较大数,可以把它取为2w,w是计算机的字长;a可以是0.01w和0.99w之间的任何整数。
应用递推公式产生均匀分布随机数时,式中参数n0,a,b,M的选取十分重要。
例如,选取M=10,a=b =n0=7,生成的随机序列为{6,9,0,7,6,9,……},周期为4。
取M=16,a=5,b =3,n0=7,生成的随机序列为{6,1,8,11,10,5,12,15,14,9,0,3,2,13,4,7,6,1……},周期为16。
取M=8,a=5,b =1,n0=1,生成的随机序列为{6,7,4,5,2,3,0,1,6,7……},周期为8。