2022年随机数生成原理实现方法不同编程语言的随机数函数 .pdf
《2022年随机数生成原理实现方法不同编程语言的随机数函数 .pdf》由会员分享,可在线阅读,更多相关《2022年随机数生成原理实现方法不同编程语言的随机数函数 .pdf(28页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、1-0: Microsoft VC+ 产生随机数的原理:Srand ( )和 Rand( )函数。它本质上是利用线性同余法,y=ax+b(mod m) 。其中 a, b,m 都是常数。因此rand 的产生决定于x, x 被称为 Seed。Seed需要程序中设定,一般情况下取系统时间作为种子。它产生的随机数之间的相关性很小,取值范围是032767(int) ,即双字节( 16 位数),若用 unsigned int 双字节是 65535,四字节是4294967295,一般可以满足要求。1-1: 线性同余法 :其中 M 是模数, A 是乘数, C 是增量,为初始值,当C=0 时,称此算法为乘同余法
2、;若C0,则称算法为混合同余法,当 C 取不为零的适当数值时,有一些优点, 但优点并不突出,故常取 C=0。模 M 大小是发生器周期长短的主要标志,常见有M 为素数,取A 为 M 的原根,则周期T=M-1 。例如:a=1220703125 a=32719 (程序中用此组数)a=16807 代码:void main( ) const int n=100; double a=32719,m=1,fn+1,gn,seed; m=pow(2,31); cout 设置 m 值为m-1endl; cout 输入种子 seed; f0=seed; for(int i=1;i=n;i+) /线性同余法生成随机
3、数 fi=fmod(a*fi-1),(m-1); gi-1=fi/(m-1); cout.setf(ios:fixed);cout.precision(6); /设置输出精度couti tgi-1endl; 结果分析:统计数据的平均值为:0.485653 统计数据的方差为:0.320576 1-2:人字映射递推公式就是有名的混沌映射中的“人字映射”或称“帐篷映射”,它的非周期轨道点的分布密度函数:人字映射与线性同余法结合,可产生统计性质优良的均匀随机数。for(int i=1;i=n;i+) /线性同余法生成随机数 fi=fmod(a*fi-1),m); if(fi=m/2) /与人字映射结合
4、生成随机数 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 28 页 - - - - - - - - - fi=2*fi; else fi=2*(m-fi)+1; 1-3:平方取中法冯?诺伊曼1946 年前后,由冯?诺伊曼提出,他的办法是去前面的随机数的平方,并抽取中部的数字。例如要生成10 位数字,而且先前的值是5772156649,平方后得到33317792380594909201,所以下一个数是7923805949。for(j=1;j=n;j+) ij=ij-1*i
5、j-1; ij=ij/pow(10,5); ij=fmod(ij,pow(10,10); gj=ij/pow(10,10); cout.setf(ios:fixed);cout.precision(6); /设置输出精度coutjtgjendl; 二:任意分布随机数的生成利用 (0,1)均匀分布的随机数可以产生任意分布的随机数。主要的方法有反函数法,舍选法, 离散逼近法, 极限近似法和随机变量函数法等。这里主要讨论了反函数法,当然对于具体分布函数可以采用不同的方法。设随机变量X 具有分布函数F(X) ,则对一个给定的分布函数值,X 的值为其中 inv 表示反函数。现假设r 是(0,1)均匀分布
6、的随机变量R 的一个值,已知R 的分布函数为因此,如果r 是 R 的一个值,则X 具有概率也就是说如果(r1,r2,.,rn) 是 R 的一组值,则相应可得到的一组值具有分布。从而,如果我们已知分布函数的反函数,我们就可以从(0, 1)分布的均匀分布随机数得到所需分布的随机数了。1-4:指数分布:指数分布的分布函数为: x0 时 ,F(x)=0 ; ,F(x)=1-exp 利用上面所述反函数法,可以求得: x= ln(1-y) ,这里不妨取常数为 1. for(int j=0;jn;j+) i=rand()%100;/ 产生从 0-32767 的任意一个值aj=double(i)/double
7、(100); aj=-log(aj);/ 常数大于0,这里取1 、 、 、 、 、 、 、名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 28 页 - - - - - - - - - 1-5:正态分布:正态分布的概率密度是:正态分布的分布函数是:对于正态分布, 利用反函数的方法来获取正态分布序列显然是很麻烦的,牵涉到很复杂的积分微分运算,同时为了方便,我们取,即标准正态分布。因此这里介绍了两种算法:第一种:Box 和 Muller 在 1958 年给出了由均匀分布的随机变
8、量生成正态分布的随机变量的算法。设U1, U2 是区间(0, 1)上均匀分布的随机变量,且相互独立。令X1=sqrt(-2*log(U1) * cos(2*PI*U2); X2=sqrt(-2*log(U1) * sin(2*PI*U2); 那么 X1, X2 服从 N(0,1) 分布,且相互独立。p=rand()%100;/ 产生从 0-32767 的任意一个值bj=double(p)/double(100); aj=sqrt(-2*log(aj)*cos(2*3.1415926*bj); 第二种:近似生成标准正态分布,独立同分布的多个随机变量和的分布趋近于正态分布,取 k 个均匀分布的 (
9、0,1) 随机变量,,,则它们的和近似服从正态分布。实践中 ,取 k=12,(因为 D( )=1/12), 则新的随机变量y=x1+x2+.+x12-6 ,可以求出数学期望E(y)=0, 方差 D(y)=12*1/12=1 ,因此可以近似描述标准正态分布这几天再看数据结构和算法,中间遇到了生成不重复的随机数的问题我先想到的一个算法是这样的:Generator(vector& vec, const int num) srand(time(NULL); vector v; int size = num; for(int i = 1; i = num; +i) v.push_back(i); for
10、(int i = 0; i num; +i) vector:iterator it = v.begin(); int n = rand() % (size-); it += n; vec.push_back(*it); v.erase(it); 但是由于vector 删除效率很低, 所以这个算法在10W 的时候已经不可接受了,需要 17 秒左右,后来在网上看到有朋友提出了另一种算法,感觉不错,于是又测试了一下名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 28 页 - -
11、 - - - - - - - void Gen(vector& vec, const int num) srand(time(NULL); for(int i = 0; i num; +i) vec.push_back(i+1); for(int i = 0; i num; +i) swap(vec.at(i), vec.at(rand() % num); 这个算法是线性的,在10W 的时候还可以,需要1.7 秒左右,可是100W 的时候就要17 秒左右了。想问一下,有没有更高效的生成算法?_ 回复:问一个关于随机数生成算法的问题lz 应该把要求说的具体点一定要 vector? _ 回复:问一
12、个关于随机数生成算法的问题同意楼上的。要生成不重复的随机数,楼主可以自己写一个随机数生成程序啊,为什么一定要用rand()函数?楼主如果真的对随机数感兴趣,建议楼主看一看Knuth 的计算机程序设计艺术第二卷。可以用线性同余法:A(n+1)=(a*A(n)+c)%M 生成取遍 1 至 M-1 的所有整数, 前提是参数a,c,M选取合适。_ 回复:问一个关于随机数生成算法的问题STL 主要目标是提供一个通用高速的算法,如果对一个专用的功能而且追求很高的效率,最好使用最原始数据类型和直接手写的算法。下面给出我刚刚写好的一个程序,在VC6 下编译通过,当n=100 万时,仅需0.78 秒。/ csd
13、n_5398401.cpp : Defines the entry point for the console application. #include stdafx.h #include memory.h #include stdlib.h #include windows.h typedef unsigned char BYTE; typedef unsigned long DWORD; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 28 页 - - - - -
14、- - - - void test(int n) int i,c; DWORD idx; DWORD *pBuff; BYTE *pMask; BYTE maskArr=1,2,4,8,16,32,64,128; /- c=(n+7)/8; pMask=new BYTEc; pBuff=new DWORDn; memset(pMask,0,sizeof(BYTE)*c); memset(pBuff,0,sizeof(DWORD)*n); for (i=1;in;) idx=(rand() x=0, if ( ( pMaskidx / 8 & maskArridx % 8) =0) / pBuf
15、fx 没有存储过任何数 pMaskidx / 8 |= maskArridx % 8;/ 置 1 pBuffidx=i; i+; /- delete pMask; delete pBuff; int main(int argc, char* argv) DWORD t=GetTickCount(); test(1000000); t=GetTickCount()-t; printf(It take %d msn,t); return 0; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - -
16、第 5 页,共 28 页 - - - - - - - - - Java 中随机数生成的几种方法java 产生随机数的几种方式在 j2se 里我们可以使用Math.random() 方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以一定的数,比如说乘以100,他就是个100 以内的随机,这个在j2me 中没有。在 java.util 这个包里面提供了一个Random 的类,我们可以新建一个Random 的对象来产生随机数,他可以产生随机整数、随机float、随机double,随机long,这个也是我们在 j2me 的程序里经常用的一个取随机数的方法。在我们的S
17、ystem 类中有一个currentTimeMillis() 方法,这个方法返回一个从1970 年 1月 1 号 0 点 0 分 0 秒到目前的一个毫秒数,返回类型是long,我们可以拿他作为一个随机数,我们可以拿他对一些数取模,就可以把他限制在一个范围之内啦其实在 Random 的默认构造方法里也是使用上面第三种方法进行随机数的产生的对于方法二中的Random 类有以下说明:java.util.Random 类有两种方式构建方式:带种子和不带种子不带种子:此种方式将会返回随机的数字,每次运行结果不一样public class RandomTest public static void mai
18、n(String args) java.util.Random r=new java.util.Random(); for(int i=0;i10;i+) System.out.println(r.nextInt(); 带种子:此种方式,无论程序运行多少次,返回结果都是一样的public static void main(String args) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 28 页 - - - - - - - - - java.util.Random
19、 r=new java.util.Random(10); for(int i=0;i10;i+) System.out.println(r.nextInt(); 两种方式的差别在于(1) 首先请打开Java Doc,我们会看到Random 类的说明:此类的实例用于生成伪随机数流,此类使用48 位的种子, 该种子可以使用线性同余公式对其进行修改(请参阅Donald Knuth 的 The Art of Computer Programming, Volume 2 ,第3.2.1 节) 。如果用相同的种子创建两个Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列
20、。为了保证实现这种特性,我们为类Random 指定了特定的算法。为了Java 代码的完全可移植性,Java 实现必须让类Random 使用此处所示的所有算法。但是允许Random 类的子类使用其他算法,只要其符合所有方法的常规协定即可。Java Doc 对 Random 类已经解释得非常明白,我们的测试也验证了这一点。(2) 如果没有提供种子数, Random 实例 的种子 数将是当前时间 的毫秒 数,可 以通过System.currentTimeMillis() 来获得当前时间的毫秒数。打开JDK 的源代码,我们可以非常明确地看到这一点。/* * Creates a new random n
21、umber generator. Its seed is initialized to * a value based on the current time: * Random() this(System.currentTimeMillis(); java.lang.System#currentTimeMillis() */ public Random() this(System.currentTimeMillis(); 另外:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页
22、,共 28 页 - - - - - - - - - random 对象的 nextInt(),nextInt(int n) 方法的说明:int nextInt() 返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的int 值。int nextInt(int n) 返回一个伪随机数,它是从此随机数生成器的序列中取出的、在 0 (包括) 和指定值(不包括)之间均匀分布的int 值。C+中随机数生成方法标准库 (被包含于 中)提供两个帮助生成伪随机数的函数:函数一: int rand(void);从 srand (seed) 中指定的 seed 开始,返回一个 seed, RAND_MAX (
23、0 x7fff ) )间的随机整数。函数二: void srand(unsigned seed);参数 seed 是 rand() 的种子,用来初始化rand() 的起始值。可以认为rand() 在每次被调用的时候,它会查看:1) 如果用户在此之前调用过srand(seed),给 seed 指定了一个值,那么它会自动调用srand(seed)一次来初始化它的起始值。2) 如果用户在此之前没有调用过srand(seed),它会自动调用srand(1)一次。根据上面的第一点我们可以得出:1) 如果希望rand()在每次程序运行时产生的值都不一样,必须给 srand(seed) 中的 seed一个变
24、值,这个变值必须在每次程序运行时都不一样(比如到目前为止流逝的时间)。2) 否则,如果给seed 指定的是一个定值,那么每次程序运行时rand()产生的值都会一样,虽然这个值会是seed, RAND_MAX(0 x7fff ) )之间的一个随机取得的值。3) 如果在调用rand() 之前没有调用过srand(seed) , 效果将和调用了srand(1) 再调用 rand()一样( 1 也是一个定值)。举几个例子,假设我们要取得06 之间的随机整数(不含6 本身):例一,不指定seed :for(int i=0;i10;i+) ran_num=rand() % 6; coutran_num ;
25、 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 28 页 - - - - - - - - - 每次运行都将输出:5 5 4 4 5 4 0 0 4 2 例二,指定seed 为定值 1:srand(1); for(int i=0;i10;i+) ran_num=rand() % 6; coutran_num ; 每次运行都将输出:5 5 4 4 5 4 0 0 4 2 跟例子一的结果完全一样。例三,指定seed 为定值 6:srand(6); for(int i=0;i1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年随机数生成原理实现方法不同编程语言的随机数函数 2022 随机数 生成 原理 实现 方法 不同 编程 语言 函数
限制150内