【学习笔记】C语言 随机数的生成原理分析和各类随机数公式

概论

百度百科给出的随机数的定义是:“随机数是专门的随机试验的结果”。当我们需要完成一个类似于抽奖的程序时,我们往往会借助随机数来实现目标,但实际情况下,计算机只能给我们提供伪随机数。
所谓伪随机数,“是按照一定算法模拟产生的,其结果是确定的,是可见的”。计算机产生随机数的过程,是根据一个种子为基准,以某个递推公式推算出来的一系列数,当递推的范围足够大、往复性足够强、又符合正态分布或平均分布时,我们就可以认为这是一个近似的真随机数
c语言中,头文件stdlib.h(c++中是cstdlib)为我们提供了rand函数来生成随机数和srand()来提供随机数种子。
所谓种子可以看作随机数序列的名字,一个种子对应一串随机数序列,当种子不变时,就会按照随机数序列依次输出随机数。

实例

1.默认种子

#include
#include
using namespace std;
#define max 1
#define min 10
int main()
{
    int i;
    for(i=0;i<10;i++){
        cout<//生成随机数
    }
    return 0;
}

结果:
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
这个代码没有指定种子,所以第一次请求时,种子被设置为1,这个我们等一下可以看到

2.为种子赋值

2.1 循环内定种子

void Rand21(){
    int i;
    for(i=0;i<10;i++){
        srand(1);
        cout<<rand()<

41
41
41
41
41
41
41
41
41
41
这次的输出结果是是个41,因为我们在每一次输出随机数之前都为种子赋值,我们也可以知道,如果种子是默认值1,那么随机数序列的第一个值是41

2.2 循环外定种子

void Rand22(){
    int i;
    srand(1);
    for(i=0;i<10;i++){
        cout<<rand()<

输出结果和第一类一致,原因是默认的种子就是1,因此如果我需要产生更类似于真随机的随机数,我们就需要让种子也变得“随机”

2.3 循环外不定种子

void Rand231(){
    int i;
    srand(time(NULL));
    for(i=0;i<10;i++){
        cout<<rand()<

输出结果请大家自己测试,如果测试的频率很高的话,会发现各次数据的情况非常类似,数值之间的间隔也小,这就是由于时间相近导致的种子之间的差异小,随机数序列的差异也小

因此我们套用两次进行运算。

void Rand232(){
    int i,j;
    srand(time(NULL));
    j=rand()+rand();
    srand(j);
    for(i=0;i<10;i++){
        cout<<rand()<

每次测试的结果之间的差距就大了很多,多次使用的随机样本更趋近于“真随机”。

3.常见的取随机值的方法

3.1 在1~n之间取随机数

void Rand31(){
    int i,n;
    cin>>n;
    for(i=0;i<10;i++){
        cout<<1+(int)(n*rand()/RAND_MAX<//本样例用默认种子

原理是rand()函数的取值范围是1~32767,所以对随机生成的数值对应比例缩小或放大,即可实现

3.2 random(int)函数

random(int)函数和rand(void)函数的区别显而易见,random(int)函数输出的是指定范围内的随机数,而相同点是也可以用randomSeed()来制定种子
但需要注意的是,random函数不是标准库函数,vc、g++等编译器是不能识别的

3.3通用随机数公式

3.3.1 a~b之间的随机数

前文所使用的公式

a+(int)(b-a)*rand()/(RAND_MAX+1)//左闭右开
a+(int)(b-a)*rand()/RAND_MAX//闭合区间

对这个公式进行改良得到

rand()%(b-a)+a//开闭区间为左闭右开
rand()%(b-a)+a+1//开闭区间为左闭右开
rand()%(b-a+1)+a//开闭区间为闭区间

再由上面我们可以得到a~a+n的通用公式

a+rand()%n//这个函数的区间问题请大家参考上面来思考

3.3.2 0~1的小数

rand()/(double)RAND_MAX

由此推得a~a+1之间的小数

rand()/(double)RAND_MAX+a

在向外发展,结合3.3.1,a~b之间的小数

rand()/(double)RAND_MAX+rand()%(b-a)+a

总结

以下要点需要在编写随机数程序过程中牢记
1.rand函数的生成结果由种子决定,种子默认为1
2.种子如果一定,那么随机的结果就会在完成一次循环后重复这一过程
3.即使不断的选取种子,所产生的数值都是伪随机,计算机无法实现真正的“真随机”

最后希望大家以后搞小活动的时候,如果需要随机数生成器,能自己编写一次属于自己的生成器,加个善意的小后门来做个小惊喜。

你可能感兴趣的:(随机数,c语言,算法)