① 线性同余算法一般认为2∧k-1比2∧k要好,这是为什么
电信彭宇算法一般认为二这个要好不知道我提都交不上去。
② 如何评价一个伪随机数生成算法的优劣
从我的角度认为,达到设计需求的随机就是优秀的无论它是真或假,是否满足那个k1234其它领域不熟就不说,就游戏领域,我认为游戏领域不需要优秀的真随机,需要的都是优秀的伪随机。酷跑,我需要随机拼接场景,道具,分值,以达到不单调重复的目的。但是我又需要控制游戏节奏,用户的体验节奏,因此我需要根据用户的得分情况,失误操作去设置一堆的阀值,来调整随机规则,让用户不断产生一种错觉,这只是失误,就差一点点,都是因为xxx同理可推,抽奖、掉落、攻击、爆击、合成等。个人以为,在实际应用领域,满足设计需求的伪随机比算法优秀的真随机优秀太多太多,当然一切前提是说明随即需求,很多时候设计者自己都说不清他的随机需求是啥,只是觉得需要随机。
③ Java怎么用线性同余法跟取余法一起产生一个序列。
乱数是不重复的随机数吗?
很多算法的每一个计算步骤都是固定的,而在下面我们要讨论的概率算法,允许算法在执行的过程中随机选择下一个计算步骤。许多情况下,当算法在执行过程中面临一个选择时,随机性选择常比最优选择省时。因此概率算法可在很大程度上降低算法的复杂度。
概率算法的一个基本特征是对所求解问题的同一实例用同一概率算法求解两次可能得到完全不同的效果。这两次求解问题所需的时间甚至所得到的结果可能会有相当大的差别。一般情况下,可将概率算法大致分为四类:数值概率算法,蒙特卡罗(Monte Carlo)算法,拉斯维加斯(Las Vegas)算法和舍伍德(Sherwood)算法。
数值概率算法常用于数值问题的求解。这类算法所得到的往往是近似解。而且近似解的精度随计算时间的增加不断提高。在许多情况下,要计算出问题的精确解是不可能或没有必要的,因此用数值概率算法可得到相当满意的解。
蒙特卡罗算法用于求问题的准确解。对于许多问题来说,近似解毫无意义。例如,一个判定问题其解为“是”或“否”,二者必居其一,不存在任何近似解答。又如,我们要求一个整数的因子时所给出的解答必须是准确的,一个整数的近似因子没有任何意义。用蒙特卡罗算法能求得问题的一个解,但这个解未必是正确的。求得正确解的概率依赖于算法所用的时间。算法所用的时间越多,得到正确解的概率就越高。蒙特卡罗算法的主要缺点就在于此。一般情况下,无法有效判断得到的解是否肯定正确。
拉斯维加斯算法不会得到不正确的解,一旦用拉斯维加斯算法找到一个解,那么这个解肯定是正确的。但是有时候用拉斯维加斯算法可能找不到解。与蒙特卡罗算法类似。拉斯维加斯算法得到正确解的概率随着它用的计算时间的增加而提高。对于所求解问题的任一实例,用同一拉斯维加斯算法反复对该实例求解足够多次,可使求解失效的概率任意小。
舍伍德算法总能求得问题的一个解,且所求得的解总是正确的。当一个确定性算法在最坏情况下的计算复杂性与其在平均情况下的计算复杂性有较大差别时,可以在这个确定算法中引入随机性将它改造成一个舍伍德算法,消除或减少问题的好坏实例间的这种差别。舍伍德算法精髓不是避免算法的最坏情况行为,而是设法消除这种最坏行为与特定实例之间的关联性。
本文简要的介绍一下数值概率算法和舍伍德算法。
首先来谈谈随机数。随机数在概率算法设计中扮演着十分重要的角色。在现实计算机上无法产生真正的随机数,因此在概率算法中使用的随机数都是一定程度上随机的,即伪随机数。
产生随机数最常用的方法是线性同余法。由线性同余法产生的随机序列a1,a2,...,an满足
a0=d
an=(ban-1+c)mod m n=1,2.......
其中,b>=0, c>=0, d>=m。d称为该随机序列的种子。
下面我们建立一个随机数类RadomNumber,该类包含一个由用户初始化的种子randSeed。给定种子之后,既可产生与之相应的随机数序列。randseed是一个无符号长整型数,既可由用户指定也可由系统时间自动产生。
const unsigned long maxshort=65536L;
const unsigned long multiplier=1194211693L;
const unsigned long adder=12345L;
class RandomNumber
{
private:
//当前种子
unsigned long randseed;
public:
//构造函数,缺省值0表示由系统自动产生种子
RandomNumber(unsigned long s=0);
//产生0-n-1之间的随机整数
unsigned short Random(unsigned long n);
//产生[0,1)之间的随机实数
double fRandom(void);
};
RandomNumber::RandomNumber(unsigned long s)
{
if(s==0)
randseed=time(0);
else
randseed=s;
}
unsigned short RandomNumber::Random(unsigned long n)
{
randseed=multiplier*randseed+adder;
return (unsigned short)((randseed>>16)%n);
}
double RandomNumber::fRandom(void)
{
return Random(maxshort)/double(maxshort);
}
函数Random在每次计算时,用线性同余式计算新的种子。它的高16位的随机性较好,将randseed右移16位得到一个0-65535之间的随机整数然后再将此随机整数映射到0-n-1范围内。
对于函数fRandom,先用Random(maxshort)产生一个0-(maxshort-1之间的整型随机序列),将每个整型随机数除以maxshort,就得到[0,1)区间中的随机实数。
下面来看看数值概率算法的两个例子:
1.用随机投点法计算π
设有一半径为r的圆及其外切四边形,如图所示。向该正方形随机投掷n个点。设落入圆内的点在正方形上均匀分布,因而所投入点落入圆内的概率为 πr^2/4r^2,所以当n足够大时,k与n之比就逼近这一概率,即π/4。由此可得使用随机投点法计算π值的数值概率算法。具体实现时,只需要在第一次象限计算即可。
double Darts(int n)
{
static RandomNumber dart;
int k=0;
for(int i=1;i<=n;i++){
double x=dart.fRandom();
double y=dart.fRandom();
if((x*x+y*y)<1)
k++;
}
return 4*k/double(n);
}
再简单举个舍伍德算法的例子。
我们在分析一个算法在平均情况下的计算复杂性时,通常假定算法的输入数据服从某一特定的概率分布。例如,在输入数据是均匀分布时,快速排序算法所需的平均时间是O(n logn)。但是如果其输入已经基本上排好序时,所用时间就大大增加了。此时,可采用舍伍德算法消除算法所需计算时间与输入实例间的这种联系。
在这里,我们用舍伍德型选择算法随机的选择一个数组元素作为划分标准。这样既能保证算法的线性时间平均性能又避免了计算拟中位数的麻烦。非递归的舍伍德型算法可描述如下:
template<class Type>
Type select(Type a[], int l, int r, int k)
{
static RandomNumber rnd;
while(true){
if(l>=r)
return a[l];
int i=l, j=l=rnd.Random(r-l+1);
Swap(a[i], a[j]);
j=r+1;
Type pivot=a[l];
while(true)
{
while(a[++i]<pivot);
while(a[--j]>pivot);
if(i>=j)
break;
Swap(a[i], a[j]);
}
if(j-l+1==k)
return pivot;
a[l]=a[j];
a[j]=pivot;
if(j-l+1<k)
{
k=k-j+l-1;
l=j+1;
}
else
r=j-1;
}
}
template <class Type>
Type Select(Type a[], int n, int k)
{
if(k<1||k>n)
throw OutOfBounds();
return select(a, 0, n-1, k);
}
平时我们一般开始考虑的是一个有着很好平均性能的选择算法,但在最坏情况下对某些实例算法效率较低。这时候我们用概率算法,将上述算法改造成一个舍伍德型算法,使得该算法对任何实例均有效。
不过在有些情况下,所给的确定性算法无法直接改造成舍伍德型算法。这时候就可以借助随机预处理技术,不改变原有的确定性算法,仅对其输入进行随机洗牌,同样可以得到舍伍德算法的效果。还是刚才的例子,换一种方法实现:
template<class Type>
void Shuffle(Type a[], int n)
{
static RandomNumber rnd;
for(int i=1;i<n;i++){
int j=rnd.Random(n-i)+i;
Swap(a[i], a[j]);
}
}
④ 计算机产生伪随机数的周期是多少算法是什么
为追求真正的随机序列,人们曾采用很多种原始的物理方法用于生成一定范围内满足精度(位数)的均匀分布序列,其缺点在于:速度慢、效率低、需占用大量存储空间且不可重现等。为满足计算机模拟研究的需求,人们转而研究用算法生成模拟各种概率分布的伪随机序列。伪随机数是指用数学递推公式所产生的随机数。从实用的角度看,获取这种数的最简单和最自然的方法是利用计算机语言的函数库提供的随机数发生器。典型情况下,它会输出一个均匀分布在0和1区间内的伪随机变量的值。其中应用的最为广泛、研究最彻底的一个算法即线性同余法。
线性同余法LCG(Linear Congruence Generator)
选取足够大的正整数M和任意自然数n0,a,b,由递推公式:
ni+1=(af(ni)+b)mod M i=0,1,…,M-1
生成的数值序列称为是同余序列。当函数f(n)为线性函数时,即得到线性同余序列:
ni+1=(a*ni+b)mod M i=0,1,…,M-1
以下是线性同余法生成伪随机数的伪代码:
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。
Visual C++中伪随机数生成机制
用VC产生随机数有两个函数,分别为rand(void)和srand(seed)。rand()产生的随机整数是在0~RAND_MAX之间平均分布的,RAND_MAX是一个常量(定义为:#define RAND_MAX 0x7fff)。它是short型数据的最大值,如果要产生一个浮点型的随机数,可以将rand()/1000.0,这样就得到一个0~32.767之间平均分布的随机浮点数。如果要使得范围大一点,那么可以通过产生几个随机数的线性组合来实现任意范围内的平均分布的随机数。
其用法是先调用srand函数,如
srand( (unsigned)time( NULL ) )
这样可以使得每次产生的随机数序列不同。如果计算伪随机序列的初始数值(称为种子)相同,则计算出来的伪随机序列就是完全相同的。要解决这个问题,需要在每次产生随机序列前,先指定不同的种子,这样计算出来的随机序列就不会完全相同了。以time函数值(即当前时间)作为种子数,因为两次调用rand函数的时间通常是不同的,这样就可以保证随机性了。也可以使用srand函数来人为指定种子数分析以下两个程序段,
程序段1:
//包含头文件
void main() {
int count=0;
for (int i=0;i<10;i++){
srand((unsigned)time(NULL));
count++;
cout<<"No"<
//包含头文件
void main() {
int count=0;
srand((unsigned)time(NULL));
for (int i=0;i<10;i++){
count++;
cout<<"No"<
No1=9694 No2=9694 No3=9694 No4=9694 No5=9694
No6=9694 No7=9694 No8=9694 No9=9694 No10=9694
程序段2的运行结果为:
No1=10351 No2=444 No3=11351 No4=3074 No5=21497
No6=30426 No7=6246 No8=24614 No9=22089 No10=21498
可以发现,以上两个程序段由于随机数生成时选择的种子的不同,运行的结果也不一样。rand()函数返回随机数序列中的下一个数(实际上是一个伪随机数序列,序列中的每一个数是由对其前面的数字进行复杂变换得到的)。为了模仿真正的随机性,首先要调用srand()函数给序列设置一个种子。为了更好地满足随机性,使用了时间函数time(),以便取到一个随时间变化的值,使每次运行rand()函数时从srand()函数所得到的种子值不相同。伪随机数生成器将作为"种子"的数当作初始整数传给函数。这粒种子会使这个球(生成伪随机数)一直滚下去。
程序段1中由于将srand()函数放在循环体内,而程序执行的CPU时间较快,调用time函数获取的时间精度却较低(55ms),这样循环体内每次产生随机数用到的种子数都是一样的,因此产生的随机数也是一样的。而程序段2中第1次产生的随机数要用到随机种子,以后的每次产生随机数都是利用递推关系得到的。 基于MFC的随机校验码生成
Web应用程序中经常要利用到随机校验码,校验码的主要作用是防止黑客利用工具软件在线破译用户登录密码,校验码、用户名、密码三者配合组成了进入Web应用系统的钥匙。在利用VC开发的基于客户机/浏览器(Client/Server)模式的应用软件系统中,为了防止非法用户入侵系统,通常也要运用随机校验码生成技术。
⑤ 想知道这两个结果的原理100 - Random(100) * Random(100) div 100; 或 100 - Random(Random(100));
线性同余法(Linear Congruential Method)
目前使用的大多数随机数发生器是线性同余发生器,它是Lehmer于1951年提出的.
其通式为 Xi+1=(a*Xi+c)mod m
Ui+1=Xi+1/m 其中a为乘子(常数),C为增量(常数),X0为种子,m为模。
线性同余法有如下特点:
(1)0≤Xi≤m-1,即Xi只能从0,1,2,……,m-1这m个整数中取值;
(2)适当选择m,a,c,可使Xi产生循环,无论X0取何值,其循环顺序是相同的。其循环周期称为发生器周期,记为P。若p=m,则称该发生器具有满周期。
这样的方法生成的是伪随机数,因为数列的前驱和后继的相关的,他服从均匀分布.
你想要的是不服从均匀分布的随机数,可以对产生的随机数列进行非线性运算,就可以得到其他分布.工程上浮从各种分布的随机数都是这样产生的.
你可以用sqrt(random(10000))试试看.
⑥ 线性同余 是什么
自己领悟把
一.计算机中随机数的产生
现在,在计算机,用来产生随机数的算法是“线性同余”法。所谓线性同余,其实就是下面两个式子。假设I就是一个随机数的序列,Ij+1与Ij的关系如下:
Ij+1 =Ij * a+c (mod m)
或是Ij+1 =Ij *a (mod m),
其中,不妨取a=16807,m=2147483647,以为一常数。写个简单的程序就是:
long r;
void scand( long v)//初始化随机种子数
{
r = v;
}
long rand()//产生随机数
{
r = (r*a + c)%m;//a,c,m为常数
return r;
}
再看一下稍复杂一点的:(Random () 的 Borland 的实现)
long long RandSeed = #### ;
unsigned long Random(long max)
{
long long x ;
double i ;
unsigned long final ;
x = 0xffffffff;
x += 1 ;
RandSeed *= ((long long)134775813);
RandSeed += 1 ;
RandSeed = RandSeed % x ;
i = ((double)RandSeed) / (double)0xffffffff ;
final = (long) (max * i) ;
return (unsigned long)final;
}
二.计算机产生的随机数不是真的随机数
[引:]我们建立了真正调用伪随机数生成器的 random()。但什么是伪随机数生成器?假定需要生成介于 1 和 10 之间的随机数,每一个数出现的几率都是一样的。理想情况下,应生成 0 到 1 之间的一个值,不考虑以前值,这个范围中的每一个值出现的几率都是一样的,然后再将该值乘以 10。请注意,在 0 和 1 之间有无穷多个值,而计算机不能提供这样的精度。
为了编写代码来实现类似于前面提到的算法,常见情况下,伪随机数生成器生成 0 到 N 之间的一个整数,返回的整数再除以 N。得出的数字总是处于 0 和 1 之间。对生成器随后的调用采用第一次运行产生的整数,并将它传给一个函数,以生成 0 到 N 之间的一个新整数,然后再将新整数除以 N 返回。这意味着,由任何伪随机数生成器返回的数目会受到 0 到 N 之间整数数目的限制。
在大多数的常见随机数发生器中,N 是 232? (大约等于 40 亿),对于 32 位数字来说,这是最大的值。换句话说,我们经常碰到的这类生成器能够至多生成 40 亿个可能值。而这 40 亿个数根本不算大,只是指尖这么大。
伪随机数生成器将作为“种子”的数当作初始整数传给函数。这粒种子会使这个球(生成伪随机数)一直滚下去。伪随机数生成器的结果仅仅是不可预测。由伪随机数生成器返回的每一个值完全由它返回的前一个值所决定(最终,该种子决定了一切)。如果知道用于计算任何一个值的那个整数,那么就可以算出从这个生成器返回的下一个值。
结果,伪随机数生成器是一个生成完全可预料的数列(称为流)的确定性程序。一个编写得很好的的 PRNG 可以创建一个序列,而这个序列的属性与许多真正随机数的序列的属性是一样的。例如:
PRNG 可以以相同几率在一个范围内生成任何数字。
PRNG 可以生成带任何统计分布的流。
由 PRNG 生成的数字流不具备可辨别的模式。
PRNG 所不能做的是不可预测。如果知道种子和算法,就可以很容易地推算出这个序列。
计算机产生的随机数一般都只是一个周期很长的数列,不是真的随机数。也就是说,随机数一般是伪随机数,每个随机数都是由随机种子开始的一个已定的数列(周期很长)。一般地,为了随机数更真一点,随机种子在系统中通常是参照系统时钟生成的。
看看下面这个例子,从中,读者应能有所体会。
main()
{
int i;
scand(time(NULL)); /*可向计算机读取其时钟值,并把值自动设为随机数种子*/
for(i=0;i<10;i++){
printf("%10d",1+(rand()%6));/*这里1是移动值,他等于所需的连续整数*/
} /*数值范围的第一个数;b是比例因子;他*/
return(0); /*等于所需的连续整数值的范围宽度;*/
}
从数学上讲,为了得到一个周期性更长的随机序列,我们可以使用如下方法:(这是我在一个书上看到的,详细的情况大家可以查一查,我自己也记不清了,呵呵)
float rand(long* im)
{
int j; long k; static long iy=0; static long iv[NTAB];
float temp;
if(*im<=0||!iy)
{
if(-(*im)<1) *im=1;
else *im=-(*im);
for(j=NTAB+7;j>=0;j--){
k=(*im)/IQ;
*im=IA*(*im-k*IQ)-k*IR;
if(*im<0)
*im+=IM;
if(j<NTAB)
iv[j]=*im;
} iy=iv[0]; }
k=(*im)/IQ;
*im=IA*(*im-k*IQ)-k*IR;
if(*im<0) *im+=IM;
j=iy/NDIV;
iy=iv[j];
iv[j]=*im;
if((temp=float(AM*iy))>RNMX) return float(RNMX);
else return temp;
}
[注:]有文讲 ,根据Randomize的工作原理,利用函数Timer得到从午夜开始到现在经过的秒数,然后再根据要得到的随机数值大小对该数值进行"“衰减”处理,这样得到的数值则可称得上是真正意义的随机数值,我认为,这也是人为的方法,仍有它的确定性和周期性,仍称不上是真正的随机数,单纯改变伪随机数的生成逻辑计算方法并不能达到目的,最有效的办法只能是改变rand_seed,就是种子。而且,改变后的rand_seed不应该是人为的。(注:目前,在 Intel 的PIII处理器中内置了一个与CPU温度相关的随机数生成器,算是一个比较有效的种子生成器。)更好的办法是根据“随机事件”生成随机数,如键盘和鼠标输入值、中断、磁盘读取等等。然而,许多服务器没有键盘和鼠标,许多“黑盒”产品也不带有硬盘,因此很难找到好的随机数源,当然,通讯密钥也就一样不安全。而如网络状态等也不能很好地保证随机数的“随机性”。电器噪声和声音频率也许是很好的随机数源,但大多数人恐怕并不愿意在计算机中增加这种设备,而且也可能出现设备失灵和外部操纵(影响)等问题。对于要处理大量连接的网关服务器,是必须要考虑的问题。如果可以通过,精确检测机器cpu的通电电流强度,来作为随机数种子,或是其他一些没有人为因素的干扰的,且瞬间变化快的方法获得种子,必将能产生符和要求的随机数。
三.几种随机数的获取办法
1.产生一个范围内的随机数
一般地,我们可用j=1+(int)(n*rand()/(RAND_MAX+1.0))来生成一个0到n之间的随机数。
若用int x = rand() % 100;来生成 0 到 100 之间的随机数这种方法是不可取的,比较好的做法是: j=(int)(100.0*rand()/(RAND_MAX+1.0)) ,当然,我们也可是使用random(100)。下面的例子都是用了random(n).
2、筛选型随机数 如希望取0-99的随机数,但不能是6。
解决方法:
x = random(100);
while (x==6) {
x = random(100);
}
又如希望取0-99的随机数,但不要5的倍数 解决方法:
x = random(100);
while ((x % 5)==0) {
x = random(100);
}
3、从连续的一段范围内取随机数。
如从40--50的范围内取随机数。 解决方法: x=random(11)+40
4、从一组乱数中取随机数。 如:从 67, 87, 34, 78, 12, 5, 9, 108, 999, 378十个数中随机取数。 解决方法:可以用数组将些十个数存贮,然后把0--9中取出的随机数作为序号,实现随机取数。
a = new Array(67, 87, 34, 78, 12, 5, 9, 108, 999, 378);
j = random(10);
x = a[j];
四.产生具有一定分布的随机数
关于这点,有一篇文章写得很好,请看:
非均匀分布随机数的产生及其在计算机模拟研究中的应用
作者:胡性本 刘向明 方积乾
单位:胡性本(湖北职工医学院 荆州434000); 刘向明(湖北职工医学院 荆州434000 现为华中理工大学生物工程系博士研究生); 方积乾(湖北职工医学院 荆州434000 中山医科大学)
关键词:非均匀分布随机数;计算机模拟;程序设计
摘 要:非均匀分布随机数在进行计算机模拟研究中有重要作用,但计算机高级语言通常都只提供产生均匀分布随机数的函数,给研究工作带来困难。该文提出的方法,较好地解决了这一问题,有很强的适用性。
中图分类号:O 242.1
文章编号:1004-4337(2000)01-0059-02▲
1 问题的提出
常用的计算机高级程序设计语言,大多提供了产生在〔0,1〕区间内连续均匀分布的独立随机数r的函数。若将产生的随机数作简单的变换X=a+(b-a)r,就能得到在区间〔a,b〕上均匀分布的随机数X。如果与取整或舍入函数结合运用,还可得到离散均匀分布的随机数,给计算机模拟提供了方便。但在很多情况下进行计算机模拟需要用到按某些特定规律分布的非均匀随机数。例如,在离子通道门控模型的模拟研究中,就经常要用到服从指数分布、对数分布、正态分布、普畦松分布等非均匀分布的随机数。这时可以在源程序中编写一个函数或过程来产生。我们在近年来所进行的计算机模拟研究工作〔1,2〕中,大量使用了非均们分布的随机数,获得成功。由于离散随机数可以由连续随机数通过取整或舍入等途径转换而得,本文只侧重介绍非均匀分布连续随机数的产生原理和应用实例,并给出了用类PASCAL语言〔3〕编写的相应的函数和过程。掌握了任何一种计算机高级语言编程技术和数据结构知识的人,都能很方便地转换成能上机运行的程序,有很大的灵活性与很强的实用性。
2 产生原理
假定连续随机变量X是连续随机变量R的函数
x= ® (1)
由概率统计知识可知,X与R在对应点的分布函数的数值应当相等,即产生R的反变换
F(x)=F® (2)
其中,r为(1)式的解,即r= -1(x)=Ψ(x)
在特殊情况下,若R是在〔0,1〕区间内的均匀分布的连续随机变量,那么R<r的概率P(R<r)=r。此时,(2)式可以简化为
F(x)=F®=r (3)
其反函数
x=F-1® (4)
具有分布函数F,现予以证明:因为分布函数是单调递增函数,其反函数存在。由概率知识可知,对任意实数X,有
P(X<x)=P(F-1(R)<x)=P(R<F(x))
因为R是在〔0,1〕区间上的均匀分布的连续随机变量,故P(R<F(x))=F(x),即F-1®具有分布函数F。
(4)式表明,要产生一个服从某种分布的随机数,可以先求出其分布函数的反函数的解析式,再将一个在〔0,1〕区间内的均匀随机数的值代入其中计算就可以了。
3 应用实例
例1 产生密度函数满足指数分布
的随机数,其中α>0。
因为 ,故分布函数为:
由(4)式可得
(5)
当r为〔0,1〕区间内的均匀随机数时,1-r也是〔0,1〕区间内的均匀随机数,故(5)式还可以简化为:
(6)
假定计算机高级语言已提供了产生在〔0,1〕区间内均匀分布的随机数的函数RND(0),则根据(6)式可以写出产生服从指数分布的随机数的类PASCAL语言的函数如下:
FUNC get_exp_random(alpha:real):real;
{产生服从指数分布的随机数,值参alpha为比例参数}
get_exp_random=-ln(RND(0))/alpha;
ENDF; {get_exp_random}
例2 产生服从正态分布的随机数
正态分布X~N(a,σ)都可以由标准的正态分布X′~N(0,1)经过变换X=a+σX′得到,在此只讨论服从标准正态分布的随机数的产生方法。标准正态分布的密度函数为:
(7)
但其分布函数不能用有限的解析形式来表示,给转换带来困难,但可以用以下的变换来产生随机数。
假定r1与r2是〔0,1〕区间的两个独立的均匀分布随机数,现将其作如下的变换,令
(8)
再将其反变换为:
(9)
(9)式中的C为常数。由此可导出其密度函数为:
(10)
比较(10)式与(7)式,可知X1与X2是两个相互独立的服从正态分布的随机变量,因而(8)式是与(4)相当的据以产生随机数的表达式。由此可以写出产生服从标准正态分布随机数的类PASCAL语言的过程如下:
PROC gauss(VAR x1,x2:real);
{产生服从正态分布的随机数对,用变量参数x1与x2传递随机数}
pi:=3.14159265; {赋π值}
r1:=RND(0); r2:=RND(0);
s:=SQRT(-2*ln(r1)); {中间变量赋值}
x1:=s*cos(2*pi*r2);
x2:=s*sin(2*pi*r2);
{正态分布随机数赋给变量参数}
ENDP; {gauss}
此过程每调用一次能产生两个相互正交的标准正态分布随机数。
⑦ 如何编程实现线性同余发生器算法生成伪随机数
#include <iostream>
#include <ctime>
using namespace std;int main(){srand(time(NULL)); //这个产生种子的函数在这个位置
for (int i=0;i<50;i++)
{ int n=rand()%10; //n1,n1,n1 cout<<n<<" ";
}
cout<<endl;
}另一个改成:#include <iostream>
#include <ctime>
using namespace std;int main(){ for (int i=0;i<50;i++)
{ srand(time(NULL)); //这个产生种子的函数在这个位置 int n=rand()%10; //n1,n1,n1 cout<<n<<" ";
}
cout<<endl;
}
⑧ 线性同余法产生伪随机数流,给定初始值:a=5,c=3,m6,种子值=5,则生成的第一个[0,1]区
摘要 您好!很高兴为您解答!
⑨ 线性同余方程的特点及求解是什么
线性同余方程 在数论中,线性同余方程是最基本的同余方程,“线性”表示方程的未知数次数是一次,即形如: 的方程。此方程有解当且仅当 b 能够被 a 与 n 的最大公约数整除(记作 gcd(a,n) | b)。这时,如果 x0 是方程的一个解,那么所有的解可以表示为: 其中d 是a 与 n 的最大公约数。在模 n 的完全剩余系 {0,1,…,n-1} 中,恰有 d 个解。 目录 1 例子 2 求特殊解 3 线性同余方程组 4 参见 例子 在方程 3x ≡ 2 (mod 6) 中, d = gcd(3,6) = 3 ,3 不整除 2,因此方程无解。 在方程 5x ≡ 2 (mod 6) 中, d = gcd(5,6) = 1,1 整除 2,因此方程在{0,1,2,3,4,5} 中恰有一个解: x=4。 在方程 4x ≡ 2 (mod 6) 中, d = gcd(4,6) = 2,2 整除 2,因此方程在{0,1,2,3,4,5} 中恰有两个解: x=2 and x=5。 求特殊解 对于线性同余方程 ax ≡ b (mod n) (1) 若d = gcd(a, n 整除 b ,那么为整数。由裴蜀定理,存在整数对 (r,s) (可用辗转相除法求得)使得 ar+sn=d,因此 是方程 (1) 的一个解。其他的解都关于与 x 同余。 举例来说,方程 12x ≡ 20 (mod 28) 中d = gcd(12,28) = 4 。注意到 ,因此 是一个解。对模 28 来说,所有的解就是 {4,11,18,25} 。 线性同余方程组 线性同余方程组的求解可以分解为求若干个线性同余方程。比如,对于线性同余方程组: 2x ≡ 2 (mod 6) 3x ≡ 2 (mod 7) 2x ≡ 4 (mod 8) 首先求解第一个方程,得到x ≡ 1 (mod 3),于是令x = 3k + 1,第二个方程就变为: 9k ≡ 1 (mod 7) 解得k ≡ 3 (mod 7)。于是,再令k = 7l + 3,第三个方程就可以化为: 42l ≡ 16 (mod 8) 解出:l ≡ 0 (mod 4),即 l = 4m。代入原来的表达式就有 x = 21(4m) + 10 = 84m + 10,即解为: x≡ 10 (mod 84) 对于一般情况下是否有解,以及解得情况,则需用到数论中的中国剩余定理。 参见 二次剩余 中国剩余定理 谈谈解线性同余方程 因为ACM/ICPC中有些题目是关于数论的,特别是解线性同余方程,所以有必要准备下这方面的知识。关于这部分知识,我先后翻看过很多资料,包括陈景润的《初等数论》、程序设计竞赛例题解、“黑书”和很多网上资料,个人认为讲的最好最透彻的是《算法导论》中的有关章节,看了之后恍然大悟。经过几天的自学,自己觉得基本掌握了其中的“奥妙”。拿出来写成文章。 那么什么是线性同余方程?对于方程:ax≡b(mod m),a,b,m都是整数,求解x 的值。 解题例程:pku1061 青蛙的约会 解题报告 符号说明: mod表示:取模运算 ax≡b(mod m)表示:(ax - b) mod m = 0,即同余 gcd(a,b)表示:a和b的最大公约数 求解ax≡b(mod n)的原理: 对于方程ax≡b(mod n),存在ax + by = gcd(a,b),x,y是整数。而ax≡b(mod n)的解可以由x,y来堆砌。具体做法,见下面的MLES算法。 第一个问题:求解gcd(a,b) 定理一:gcd(a,b) = gcd(b,a mod b) 实现:古老的欧几里德算法 int Euclid(int a,int b) { if(b == 0) return a; else return Euclid(b,mod(a,b)); } 附:取模运算 int mod(int a,int b) { if(a >= 0) return a % b; else return a % b + b; } 第二个问题:求解ax + by = gcd(a,b) 定理二:gcd(b,a mod b) = b * x' + (a mod b) * y' = b * x' + (a - a / b * b) * y' = a * y' + b * (x' - a / b * y') = a * x + b * y 则:x = y' y = x' - a / b * y' 实现: triple Extended_Euclid(int a,int b) { triple result; if(b == 0) { result.d = a; result.x = 1; result.y = 0; } else { triple ee = Extended_Euclid(b,mod(a,b)); result.d = ee.d; result.x = ee.y; result.y = ee.x - (a/b)*ee.y; } return result; } 附:三元组triple的定义 struct triple { int d,x,y; }; 第三个问题:求解ax≡b(mod n) 实现:由x,y堆砌方程的解 int MLES(int a,int b,int n) { triple ee = Extended_Euclid(a,n); if(mod(b,ee.d) == 0) return mod((ee.x * (b / ee.d)),n / ee.d); else return -1; }//返回-1为无解,否则返回的是方程的最小解 说明:ax≡b(mod n)解的个数: 如果ee.d 整除 b 则有ee.d个解; 如果ee.d 不能整除 b 则无解。
求采纳