20201123-C语言补充-随机数-让自己的程序更好玩-充满意外

C语言下的随机数

1. 相关头和函数

  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <time.h>
  • srand(time(NULL));// 利用时间函数产生随机种子
  • data[i] = rand()%999+2;//产生2-1000闭区间的随机赋,并完成对数组元素的赋值操作

一般使用 <stdlib.h> 头文件中的 rand() 函数来生成随机数

  • rand() 会随机生成一个位于 0 ~ RAND_MAX 之间的整数
    • 它生成的基本上算是0-RAND_MAX之间的等概率随机数列了

还有一个 random() 函数可以获取随机数,但是 random() 不是标准函数,不能在 VC/VS 等编译器通过,所以比较少用。

先来个例子

#include <stdio.h>
#include <stdlib.h>
int main(){
    
    
    int a = rand();
    printf("%d\n",a);
    return 0;
}

2. 随机数用于哪些地方

  • 测试数据,大量的测试数据
  • 模拟自然状态下的符合正态分布的精力情形
  • 让计算机看起来“智能化”,会猜出,会出牌,会做一些像人一样的随机行为
    • 贪吃蛇游戏中在随机的位置出现食物
    • 扑克牌游戏中随机发牌
    • 剪刀石头布的游戏
    • 猜数字游戏

3. 随机数的本质

实际上,rand() 函数产生的随机数是伪随机数,是根据一个数值按照某个公式推算出来的,这个数值我们称之为“种子”。种子和随机数之间的关系是一种正态分布,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4zw0Co0I-1607311299897)(20201123-C语言补充-随机数.assets/image-20201123140720054.png)]

种子在每次启动计算机时是随机的,但是一旦计算机启动以后它就不再变化了;也就是说,每次启动计算机以后,种子就是定值了,所以根据公式推算出来的结果(也就是生成的随机数)就是固定的。

4. 重新播种

我们可以通过 srand() 函数来重新“播种”,这样种子就会发生改变。srand() 的用法为:

void srand (unsigned int seed);

它需要一个 unsigned int 类型的参数。在实际开发中,我们可以用时间作为参数,只要每次播种的时间不同,那么生成的种子就不同,最终的随机数也就不同。

使用 <time.h> 头文件中的 time() 函数即可得到当前的时间(精确到秒),就像下面这样:

srand((unsigned)time(NULL));

time()函数,值得注意的是time函数的形参,这个形参是个指针变量,通常写为time(NULL)。
这个函数的功能是,返回自1970年1月1日00:00:00到你先在电脑运行的时间(例:2018年3月24日14:14:00)之间的时间。

这个数是随机的,随着你电脑运行时间而发生改变。

srand()函数是伪随机数发生器种子,它给rand()函数一个产生一个起点。在单独使用rand()函数的时候,它将1作为默认参数。srand()的形参是一个无符号的类型,即unsigned类型,可以是int,float,char等等。
但在这里为了达到随机数效果,将使用time()函数来产生一个起点,它直接作用于rand()函数。

具体示例

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
    
    
    int a;
    srand((unsigned)time(NULL));
    a = rand();
    printf("%d\n", a);
    return 0;
}

5.生成一定范围内的随机数

在实际开发中,往往需要一定范围内的随机数,过大或者过小都不符合要求,那么,如何产生一定范围的随机数呢?可以利用取模的方法:

int a = rand() % 10;    //产生0~9的随机数,注意10会被整除

如果要规定上下限:

int a = rand() % 51 + 13;    //产生13~63的随机数

分析:

  • 取模即取余,rand()%51+13
  • 可以看成两部分:
    • rand()%51是产生 0~50 的随机数
    • 后面+13保证 a 最小只能是 13,最大就是 50+13=63。

具体示例

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    
    
    int a;
    srand((unsigned)time(NULL));
    a = rand() % 51 + 13;
    printf("%d\n",a);
    return 0;
}

6. 连续生成随机数

有时候业务需要一组随机数(多个随机数),该怎么生成呢?

很容易想到的一种解决方案是使用循环,每次循环都重新播种,请看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
    
    
    int a, i;
    //使用for循环生成10个随机数
    for (i = 0; i < 10; i++) {
    
    
        srand((unsigned)time(NULL));
        a = rand();
        printf("%d ", a);
    }
    return 0;
}

运行结果是:

PS E:\clangstudy\class02> cd "e:\clangstudy\randData\" ; if ($?) {
    
     gcc 'getRandData01.c' -o 'getRandData01.exe' -Wall -g -O2 -static-libgcc -std=c11 -fexec-charset=utf-8 } ; if ($?) {
    
     &'.\getRandData01' }
7077 7077 7077 7077 7077 7077 7077 7077 7077 7077

运行结果非常奇怪,每次循环都重新播种了呀,为什么生成的随机数都一样呢?

这是因为,CPU越来越好,程序运行速度非常快,在一秒之内就运行完成了,而 time() 函数得到的时间只能精确到秒,所以每次循环得到的时间都是一样的,这样一来,种子也就是一样的,随机数也就一样了。

7. 有趣的随机数程序实例

这是一个电脑自己猜数字的小程序。

  • 计算机自己产生随机数
  • 计算机自己猜出这个数
#include<stdio.h>
#include<time.h>
#include<process.h>
#include<stdlib.h>
#include<Windows.h>

int main()
{
    
    
    int ret = 0;
    int guess = 0;
    int left = 0;
    int right = 100;
    
    srand((unsigned int)time(NULL));
    ret = rand() % 100;
    printf("提供的答案数是->%d\n",ret);
    guess = 50;
    while (1)
    {
    
    
        if (guess > ret)
        {
    
    
            printf("猜大了->%d\n", guess);
            right = guess;
            guess = (right + left) / 2;
            Sleep(1000);
        }
        else if (guess < ret)
        {
    
    
            printf("猜小了->%d\n", guess);
            left = guess;
            guess = (right + left) / 2;
            Sleep(1000);
        }
        if (guess == ret)
        {
    
    
            printf("猜到了是%d", guess);
            break;
        }
    }
    system("pause ");
    return 0;
}

这里使用了二分法的思想,让电脑自己去猜100以内的一个数。
使用了Sleep()函数用来延迟一下打印时间,Sleep()函数的参数的单位是ms,所以1000ms=1s。

8. 如果种子重复了呢

据说如果软件一直开两天,种子会有1/(606024)个可能会重复,虽说这对于一般人已经绝对足够了,但纵然人不舒服

为什么总是生成一个数???因为此程序产生一个随机数之前,都调用一次srand,而由于计算机运行很快,所以每用time得到的时间都是一样的(time的时间精度较低,只有55ms)。这样相当于使用同一个种子产生随机序列,所以产生的随机数总是相同的。把srand放在循环外看看:
srand( (unsigned)time( NULL ) );
for(int i=0;i<100000;i++)
问题解决了:)

猜你喜欢

转载自blog.csdn.net/matrixbbs/article/details/110801458