出处:http://www.cnblogs.com/xkfz007/archive/2012/03/27/2420154.htmlhtml
古老的LCG(linear congruential generator)表明了最好最朴素的伪随机数产生器算法。主要缘由是容易理解,容易实现,并且速度快。 ios
LCG 算法数学上基于公式:git
X(n+1) = (a * X(n) + c) % m算法
其中,各系数为:dom
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。
通常而言,高LCG的m是2的指数次幂(通常2^32或者2^64),由于这样取模操做截断最右的32或64位就能够了。多数编译器的库中使用了该理论实现其伪随机数发生器rand()。函数
下面是部分编译器使用的各个参数值:post
Sourceui |
m加密 |
aspa |
c |
rand() / Random(L)的种子位 |
Numerical Recipes |
2^32 |
1664525 |
1013904223 |
|
Borland C/C++ |
2^32 |
22695477 |
1 |
位30..16 in rand(), 30..0 in lrand() |
glibc (used by GCC) |
2^32 |
1103515245 |
12345 |
位30..0 |
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++ |
2^32 |
1103515245 |
12345 |
位30..16 |
Borland Delphi, Virtual Pascal |
2^32 |
134775813 |
1 |
位63..32 of (seed * L) |
Microsoft Visual/Quick C/C++ |
2^32 |
214013 |
2531011 |
位30..16 |
Apple CarbonLib |
2^31-1 |
16807 |
0 |
见Park–Miller随机数发生器 |
LCG不能用于随机数要求高的场合,例如不能用于Monte Carlo模拟,不能用于加密应用。
LCG有一些严重的缺陷,例如若是LCG用作N维空间的点坐标,这些点最多位于m1/n超平面上(Marsaglia定理),这是因为产生的相继X(n)值的关联所致。
另一个问题就是若是m设置为2的指数,产生的低位序列周期远远小于总体。
通常而言,输出序列的基数b中最低n位,bk = m (k是某个整数),最大周期bn.
有些场合LCG有很好的应用,例如内存很紧张的嵌入式中,电子游戏控制台用的小整数,使用高位能够胜任。
(2) C语言中伪随机数生成方法:rand(),srand(time(null))的解析
C语言中伪随机数生成算法其实是采用了"线性同余法"。具体的计算以下:
Xi = (Xi-1 * A + C ) mod M
其中A,C,M都是常数(通常会取质数)。当C=0时,叫作乘同余法。引出一个概念叫seed,它会被做为X0被代入上式中,而后每次调用rand()函数都会用上一次产生的随机值来生成新的随机值。能够看出实际上用rand()函数生成的是一个递推的序列,一切值都来源于最初的 seed。因此当初始的seed取同样的时候,获得的序列都相同。
C语言里面有RAND_MAX这样一个宏,定义了rand()所能获得的随机值的范围。在C里能够看到RAND_MAX被定义成0x7fff,也就是32767。rand()函数里递推式中M的值就是32767。
线性同余法生成的是伪随机数,粗略符合均匀分布。根据中心极限定理,任何分布的噪声,经过反复相加,就能够成为高斯噪声。
函数原型
一、C++标准函数库提供一随机数生成器rand,返回0-RAND_MAX之间均匀分布的伪随机整数。 RAND_MAX必须至少为32767。rand()函数不接受参数,默认以1为种子(即起始值)。随机数生成器老是以相同的种子开始,因此造成的伪随机数列也相同,失去了随机意义。(但这样便于程序调试)
二、C++中另外一函数srand(),能够指定不一样的数(无符号整数变元)为种子。可是若是种子相同,伪随机数列也相同。一个办法是让用户输入种子,可是仍然不理想。
三、 比较理想的是用变化的数,好比时间来做为随机数生成器的种子。time的值每时每刻都不一样。因此种子不一样,因此,产生的随机数也不一样。
// C++随机函数(VC program)
#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
#define MAX 100
int main(int argc, char* argv[])
{
srand( (unsigned)time( NULL ) );//srand()函数产生一个以当前时间开始的随机种子.应该放在for等循环语句前面 否则要很长时间等待
for (int i=0;i<10;i++)
cout<<rand()%MAX<<endl;//MAX为最大值,其随机域为0~MAX-1
return 0;
}
rand()不须要参数,它会返回一个从0到最大随机数的任意整数,最大随机数的大小一般是固定的一个大整数。这样,若是你要产生0~10的10个整数,能够表达为:
int N = rand() % 11;
这样,N的值就是一个0~10的随机数,若是要产生1~10,则是这样:
int N = 1 + rand() % 11;
总结来讲,能够表示为:
a + rand() % n
其中的a是起始值,n是整数的范围。
a + rand() % (b-a+1) 就表示a~b之间的一个随机数
若要0~1的小数,则能够先取得0~10的整数,而后均除以10便可获得随机到十分位的10个随机小数,若要获得随机到百分位的随机小数,则须要先获得0~100的10个整数,而后均除以100,其它状况依此类推。
一般rand()产生的随机数在每次运行的时候都是与上一次相同的,这是有意这样设计的,是为了便于程序的调试。若要产生每次不一样的随机数,可使用srand( seed )函数进行随机化,随着seed的不一样,就可以产生不一样的随机数。
如你们所说,还能够包含time.h头文件,而后使用srand(time(0))来使用当前时间使随机数发生器随机化,这样就能够保证每两次运行时能够获得不一样的随机数序列(只要两次运行的间隔超过1秒)。