十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
计算机不会产生绝对随机的随机数,计算机只能产生“伪随机数”。其实绝对随机的随机数只是一种理想的随机数,即使计算机怎样发展,它也不会产生一串绝对随机的随机数。计算机只能生成相对的随机数,即伪随机数。
成都创新互联-专业网站定制、快速模板网站建设、高性价比堆龙德庆网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式堆龙德庆网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖堆龙德庆地区。费用合理售后完善,十年实体公司更值得信赖。
伪随机数并不是假随机数,这里的“伪”是有规律的意思,就是计算机产生的伪随机数既是随机的又是有规律的。怎样理解呢?产生的伪随机数有时遵守一定的规律,有时不遵守任何规律;伪随机数有一部分遵守一定的规律;另一部分不遵守任何规律。比如“世上没有两片形状完全相同的树叶”,这正是点到了事物的特性,即随机性,但是每种树的叶子都有近似的形状,这正是事物的共性,即规律性。从这个角度讲,你大概就会接受这样的事实了:计算机只能产生伪随机数而不能产生绝对随机的随机数。
随机函数有如下两种:
rand()函数返回0到RAND_MAX之间的伪随机数(pseudorandom)。RAND_MAX常量被定义在stdlib.h头文件中。其值等于32767,或者更大。
srand()函数使用自变量n作为种子,用来初始化随机数产生器。只要把相同的种子传入srand(),然后调用rand()时,就会产生相同的随机数序列。因此,我们可以把时间作为srand()函数的种子,就可以避免重复的发生。如果,调用rand()之前没有先调用srand(),就和事先调用srand(1)所产生的结果一样。
原理太高深,提供方法是可以的
1、
在C++中可以的,函数是这样用,比如0至1的随机数
Random ran=new Random();
int RandKey=ran.Next(0,1);
不过这样会有重复,可以给Random一个系统时间做为参数,以此产生随机数,就不会重复了
System.Random a=new Random(System.DateTime.Now.Millisecond);
int RandKey =a.Next(10);
2、
在EXCEL中也有相应的函数
RAND( )
注解
若要生成 a 与 b 之间的随机实数:
=RAND()*(b-a)+a
如果要使用函数 RAND 生成一随机数,并且使之不随单元格计算而改变,可以在编辑栏中输入“=RAND()”,保持编辑状态,然后按 F9,将公式永久性地改为随机数。
示例
RAND() 介于 0 到 1 之间的一个随机数(变量)
复制到其它单元格中就可以同时产生多个
问:怎样产生随机数?
答: 在计算机中并没有一个真正的随机数发生器,但是可以做到使产生的数字重复率很低,这样看起来好象是真正的随机数,实现这一功能的程序叫伪随机数发生器。
有关如何产生随机数的理论有许多,如果要详细地讨论,需要厚厚的一本书的篇幅。不管用什么方法实现随机数发生器,都必须给它提供一个名为“种子”的初始值。而且这个值最好是随机的,或者至少这个值是伪随机的。“种子”的值通常是用快速计数寄存器或移位寄存器来生成的。
下面讲一讲在C语言里所提供的随机数发生器的用法。现在的C编译器都提供了一个基于ANSI标准的伪随机数发生器函数,用来生成随机数。它们就是rand()和srand()函数。这二个函数的工作过程如下:
1) 首先给srand()提供一个种子,它是一个unsigned int类型,其取值范围从0~65535;
2) 然后调用rand(),它会根据提供给srand()的种子值返回一个随机数(在0到32767之间)
3) 根据需要多次调用rand(),从而不间断地得到新的随机数;
4) 无论什么时候,都可以给srand()提供一个新的种子,从而进一步“随机化”rand()的输出结果。
这个过程看起来很简单,问题是如果你每次调用srand()时都提供相同的种子值,那么,你将会得到相同的随机数序列,这时看到的现象是没有随机数,而每一次的数都是一样的了。例如,在以17为种子值调用srand()之后,在首次调用rand()时,得到随机数94。在第二次和第三次调用rand()时将分别得到26602和30017,这些数看上去是很随机的(尽管这只是一个很小的数据点集合),但是,在你再次以17为种子值调用srand()后,在对于rand()的前三次调用中,所得的返回值仍然是在对94,26602,30017,并且此后得到的返回值仍然是在对rand()的第一批调用中所得到的其余的返回值。因此只有再次给srand()提供一个随机的种子值,才能再次得到一个随机数。
下面的例子用一种简单而有效的方法来产生一个相当随机的“种子”值----当天的时间值:
随机数产生原理 原创
2017-06-30 18:15:46
 8点赞

大作家佚名 
码龄13年
关注
引言
利用数学的方法产生随机数的优点具有速度快、可对模拟问题进行复算检查、具有较好的统计特性。通过检验符合均匀性、随机性、独立性就可以当作真正的随机数。
随机数
经典的随机数产生方法为是线性同余法,即Linear Congruence Generator (LCG),由Lehmer于1951年提出。
同余:对于两个整数A、BA、B,如果它们同时除以一个自然数M的余数相同,就说A、BA、B对于模M同余,A≡BmodMA≡BmodM。
线性同余法
线性同余发生器是用不连续分段线性方程计算产生伪随机数序列的算法。LCG背后的理论比较容易理解,易于实现。由于计算机产生的随机数都是伪随机数,后面就直接用随机数代替伪随机数的叫法。
LCG定义如下:
Xn+1=(aXn+c)modm
Xn+1=(aXn+c)modm
其中,
XX是随机数序列
m,0mm,0m,模
a,0ama,0am,乘子
c,0≤cmc,0≤cm,增量,也叫做偏移量
X0,0≤X0mX0,0≤X0m,开始值,通常叫做“种子”seed
生成器不断往复运行,将会产生一序列script type="math/tex" id="MathJax-Element-10" a,c,ma,c,m取值合适,序列最大周期将达到 mm。这种情况下,序列中所有可能的整数都在某点固定出现。当c=0c=0时候,LCG就变换成了乘法同余发生器,multiplicative congruential generator (MCG), c≠0c≠0时叫做混合同余发生器,mixed congruential generator,MCG。
这里就用Wiki中的列子说明LCG是如何工作的:

当m=9,a=2,c=0,seed=1m=9,a=2,c=0,seed=1时,得:
X0=seed=1X0=seed=1
X2=(a∗X1+c)modm=(2×1+0)%9=2X2=(a∗X1+c)modm=(2×1+0)%9=2
X3=(a∗X2+c)modm=(2×2+0)%9=4X3=(a∗X2+c)modm=(2×2+0)%9=4
X4=(a∗X3+c)modm=(2×4+0)%9=8X4=(a∗X3+c)modm=(2×4+0)%9=8
X5=(a∗X4+c)modm=(2×8+0)%9=7X5=(a∗X4+c)modm=(2×8+0)%9=7
X6=(a∗X5+c)modm=(2×7+0)%9=5X6=(a∗X5+c)modm=(2×7+0)%9=5
X7=(a∗X6+c)modm=(2×5+0)%9=1X7=(a∗X6+c)modm=(2×5+0)%9=1
一个周期结束,如果再继续的话,随机序列将会以周期6重复出现。改变a,c,ma,c,m的值,LCG的周期性也发生了变换。
混合同余发生器 (MCG) 周期长度
通常MCG最大周期位mm,往往由于a,c,ma,c,m的选择使得周期无法达到mm。若想获得最大周期的随机数序列,需要同时满足下述条件:
m和c互质m和c互质。互质整数:公约数只有1的两个整数,如:7,5
a−1可以被ma−1可以被m的所有素因子整除
如果m被4整除,a−1也被4整除如果m被4整除,a−1也被4整除
这三个条件被称为Hull-Dobell定理,虽然LCG能够产生可以通过随机性的正式测试的伪随机数,但对参数c,m和ac,m和a的选择非常敏感。
使用LCG可能出现的问题
历史上,糟糕的因子选择导致了LCG的实施效率低下。在连续调用时,也无法避免序列的相关性。如果我们要自己设计LCG,选择不合适的a,c,ma,c,m往往带来糟糕的结果,却不自知。
历史上有这样的例子RANDU,其中,a=65539,m=231a=65539,m=231,在IBM大型机上使用了许多年,并被广泛应用在其他系统上,现在出现了很多问题,由于使用了糟糕的因子。
ANSI C库中的LCG
ANSI C库中的LCG实现具有一定的缺陷,其中一定数量的实施方法不能很好的工作,这个责任应该由ANSI C委员会及其实施者承担。——“Numerical Recipes”。该评判有明确出处,非笔者臆断!
由ANSI C标准规定rand()返回一个整数值,RAND_MAX通常不是很大。ANSI C标准要求RAND_MAX最大32767。
打开头文件stdlib.h,可以看到定义的十六进制RAND_MAX,使用博客的方法转换为十进制为32767。
/* Maximum value that can be returned by the rand function. */
#define RAND_MAX 0x7fff
1
2
3
1
2
3
ANSI C定义的LCG
打开rand.h头文件查看随机数生成器代码,产生随机数的过程即线性同余法,代码简单、结构清楚清楚。
/***
*rand.c - random number generator
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines rand(), srand() - random number generator
*
*******************************************************************************/
#include cruntime.h
#include mtdll.h
#include stddef.h
#include stdlib.h
/***
*void srand(seed) - seed the random number generator
*
*Purpose:
* Seeds the random number generator with the int given. Adapted from the
* BASIC random number generator.
*
*Entry:
* unsigned seed - seed to seed rand # generator with
*
*Exit:
* None.
*
*Exceptions:
*
*******************************************************************************/
void __cdecl srand (
unsigned int seed
)
{
_getptd()-_holdrand = (unsigned long)seed;
}
/***
*int rand() - returns a random number
*
*Purpose:
* returns a pseudo-random number 0 through 32767.
*
*Entry:
* None.
*
*Exit:
* Returns a pseudo-random number 0 through 32767.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl rand (
void
)
{
_ptiddata ptd = _getptd();
return( ((ptd-_holdrand = ptd-_holdrand * 214013L
+ 2531011L) 16) 0x7fff );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
调用方式:
#include iostream
#include random
#include time.h
using namespace std;
void main(){
//srand((unsigned)time(NULL));
srand(11);
for (int i = 0; i 10; i++)
cout rand() '\t';
cout endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
均匀分布随机数
均匀分布随机数即等概率随机数,如:扔骰子、掷硬币。使用《数值方法》中的LCG生成服从[0,1][0,1]分布的均匀分布。
#include iostream
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
#define NTAB 32
#define NDIV (1+(IM-1)/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)
float ran1(long *idum)
{
int j;
long k;
static long iy = 0;
static long iv[NTAB];
float temp;
if (*idum = 0 || !iy) {
if (-(*idum) 1)
*idum = 1;
else
*idum = -(*idum);
for (j = NTAB + 7; j = 0; j--) {
k = (*idum) / IQ;
*idum = IA*(*idum - k*IQ) - IR*k;
if (*idum 0)
*idum += IM;
if (j NTAB)
iv[j] = *idum;
}
iy = iv[0];
}
k = (*idum) / IQ;
*idum = IA*(*idum - k*IQ) - IR*k;
if(*idum 0)
*idum += IM;
j = iy / NDIV;
iy = iv[j];
iv[j] = *idum;
if ((temp = AM*iy) RNMX)
return RNMX;
else
return temp;
}
void main()
{
float ran1(long *idum);
long seed = 10;
for (int i = 0; i 10;++i)
{
std::cout ran1(seed) std::endl;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
标准正态分布随机数
现实生活中更多的随机现象是服从正态分布的,如:20岁的成年人体重分布。正太分布随机数可以通过Box-Muller方法从均匀分布随机数转换为标准正态分布随机数。下面代码是《数值方法》中完整代码。
#include iostream
#include math.h
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
#define NTAB 32
#define NDIV (1+(IM-1)/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)
float ran1(long *idum)
{
int j;
long k;
static long iy = 0;
static long iv[NTAB];
float temp;
if (*idum = 0 || !iy) {
if (-(*idum) 1)
*idum = 1;
else
*idum = -(*idum);
for (j = NTAB + 7; j = 0; j--) {
k = (*idum) / IQ;
*idum = IA*(*idum - k*IQ) - IR*k;
if (*idum 0)
*idum += IM;
if (j NTAB)
iv[j] = *idum;
}
iy = iv[0];
}
k = (*idum) / IQ;
*idum = IA*(*idum - k*IQ) - IR*k;
if(*idum 0)
*idum += IM;
j = iy / NDIV;
iy = iv[j];
iv[j] = *idum;
if ((temp = AM*iy) RNMX)
return RNMX;
else
return temp;
}
float gasdev(long *idum){
float ran1(long *idum);
static int iset = 0;
static float gset;
float fac, rsq, v1, v2;
if (*idum 0)
iset = 0;
if (iset == 0) {
do {
v1 = 2.0*ran1(idum) - 1.0;
v2 = 2.0*ran1(idum) - 1.0;
rsq = v1*v1 + v2*v2;
} while (rsq = 1.0 || rsq == 0.0);
fac = sqrt(-2.0*log(rsq) / rsq);
gset = v1*fac;
iset = 1;
return v2*fac;
}
else {
iset = 0;
return gset;
}
}
void main()
{
float ran1(long *idum);
long seed = 10;
for (int i = 0; i 10;++i)
{
std::cout gasdev(seed) std::endl;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
总结
这里详细叙述了LCG生成均匀分布随机数的方法,分析了获得最大周期的条件。随机序列具体服从的分布,可以通过卡方检验得到。由于ANSI C中的LCG随机数的缺陷,vs下编程不建议使用系统自带的随机数生成器。如果只是单独的使用LCG产生随机数,也不建议自己实现LCG(即使实现过程很简单)。最后建议使用《数值方法》中的LCG随机数生成器。
参考
Press, W. H. (2007). Numerical recipes 3rd edition: The art of scientific computing. Cambridge university press.
const NUM int = 100
for i := 0; i NUM; i += 1 {
rand.Seed(int64(i))
fmt.Printf("%d\t", rand.Int63n(int64(NUM)))
}
其实在循环里面这点时间间隔,纳秒也是跟不上的。
还有,你用sleep的方法肯定是不能接受的!!!
math/rand 中的所有整数函数都生成非负数.
示例 main.go
执行
同理,需要int64 int32类型的随机数只要修改随机函数
但是需要注意 math/rand 几个函数的取值区间!如Intn的范围[0, n)。[0,20),20会取不到
我自己的需求这样写已足够