文档章节

C Primer Plus 第12章 12.4 随机数函数和静态变量

idreamo
 idreamo
发布于 2016/11/24 05:59
字数 1448
阅读 26
收藏 0
点赞 0
评论 0

首先,来看一个随机数函数,该函数使用了一个具有内部链接的静态变量。ANSI C程序库提供了rand()函数来产生随机数。有多种随机数的算法,ANSI C 标准允许C实现使用针对特定机器的最佳算法。不过ANSI C也提供了一个可移植的标准算法,可以在不同的系统中产生相同的随机数。事实上rand()是一个“伪随机数发生器”,这意味着可以预测数字的实际顺序(计算机不具有自发性),但这些数字在可能的取值范围内均匀地分布。

为了看清楚程序内部发生了什么, 我们使用可移植的ANSI版本程序,而不是编译器内置的rand()函数。这一方案始于一个称为“种子”的数字。函数使用这个种子来产生一个新数,而这个新数又称为新的种子。接着这个新种子被用来产生一个更新的种子,依此类推。这种方案要想行之有效,随机数函数必须记下上次被调用时所使用的种子。对,这需要一个静态变量。程序清单12.7中的程序是版本0(很快您将看到版本1)。

程序清单12.7 rand0.c 函数文件

/* rand0.c --产生随机数    */
/* ANSI C 的可移植算法     */
static unsigned long int next = 1;  /*种子*/
int rand0(void)
{
/*产生伪随机数的魔术般的公式    */
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

在程序清单12.7中静态变量next的初始值为1,在每次调用函数时它的值被一个魔术般的公式修改。结果是一个从0到32767范围内的返回值。注意next是静态、具有内部链接的,而不只是静态、空链接的。这是为了稍后在将本例扩展时,便于next为同一文件中的两个函数共享。

我们用程序清单12.8所示的简单驱动程序来测试一下rand0()函数

程序清单12.8  r_drive0.c驱动程序

/*r_drive0.c --测试rand0()函数*/
/*与rand0.c一起编译*/
#include <stdio.h>
extern int rand0(void);

int main(void)
{
    int count;

    for(count=0;count<5;count++)
        printf("%hd\n",rand0());

    return 0;
}

现在又有一个机会来练习使用多文件。程序清单12.7和程序清单12.8分别使用一个文件。关键字extern提醒您rand0()在一个单独的文件中定义。

输出如下:

16838
5758
10113
17515
31051

输出看起来像随机的。但让我们再来运行一次,这次结果如下:

16838
5758
10113
17515
31051

看起来很像,这就是“伪”的特征了。每次运行主程序时,都从同一个种子值1开始。可以通过引入允许重置种子的第二个函数srand1()来解决这个问题。关键是使next成为一个具有内部链接的静态变量,亲只对rand1()和srand1()可见(C程序库中与srand1()等效的函数被称为srand())。把srand1()添加到包含rand1()的文件中。程序清单12.9给出了修改后的程序。

/*s_and_r.c  --包含函数rand1()和srand1()的文件*/
/*使用ANSI C 的可移植算法*/
static unsigned long int next = 1;  /*种子*/
int rand1(void)
{
    /*产生随机数的魔术般的公式*/
    next = next*1103515245 + 12345;
    return (unsigned int)(next/65536)%32768;
}

void srand1(unsigned int seed)
{
    next = seed;
}

注意next是一个具有内部链接的文件作用域变量。这意味着它可以同时被rand1()和srand1()使用,但不可以被其他文件中的函数使用。使用清单12.10中的驱动程序来测试这些函数。

程序清单12.10 r_drive1.c  程序

/* r_drive1.c  测试函数rand1()和srand1()  */
/*与s_and_r.c 一起编译*/
#include <stdio.h>
extern void srand1(unsigned int x);
extern int rand1(void);

int main(void)
{
    int count;
    unsigned seed;

    printf("Please enter your choice for seed.\n");
    while(scanf("%u",&seed)==1)
    {
        srand1(seed);  /*重置种子*/
        for(count=0;count<5;count++)
        printf("%hd\n",rand1());
        printf("Please enter next seed(q to quit): \n");
    }
    printf("Done\n");
    return 0;
}

又使用了两个文件。运行一次程序。

please enter your choice for seed.
1
16838
5758
10113
17515
31051
please enter your choice for seed:
3
20067
23475
8955
20841
15324
please enter your choice for seed:
q
Done

将1作为seed的值,产生了与前面相同的结果。现在来尝试将3作为seed的值:

如果您的C实现允许您访问系统时钟这种不断变化的量,可以用它们的值(可能需要截断)来初始化种子值。例如,ANSI C有一个函数time()可以返回系统时间。时间单位由系统决定,但有用的一点是返回值为数值类型,并且随着时间变化。其确切类型与系统有关,名称为time_t,但您可以对它进行类型指派。下面是基本思路:

#include <time.h>                     /*为time()函数提供ANSI原型*/
    srand1((unsigned int) time(0))    /*初始化种子*/

通常,time()的参数是一个time_t类型对象的地址。那种情形下,时间值也存储在那个地址中。然而,您也可以传送空指针(0)作为参数。此时,时间值仅通过返回值机制提供。

可以对标准的ANSI C函数srand()和rand()使用同样的技术。使用这些函数地,要包括stdlib.h头文件。实际上,既然已经知道srand1()和rand1()如何使用一个具有内部链接的静态变量,您同样也可以使用您的编译器提供的版本。我们将在下一个例子中这样做。

 

© 著作权归作者所有

共有 人打赏支持
idreamo
粉丝 12
博文 139
码字总数 224743
作品 0
青岛
产品经理
C Primer Plus 第12章 存储类、链接和内存管理

12.1 存储类 C为变量提供了5种不同的存储模型,或称为存储类。还有基于指针的第6种存储模型,本章稍后(“分配内存malloc()和free()”小节)将会提到。可以按照一个变量(更一般地,一个数据...

idreamo
2016/11/01
18
0
C Primer Plus 第12章 12.5 掷骰子

掷骰子最普遍的形式是用两个6面骰子。 计算机可以设计一种具有任意面数的骰子,先从6面开始,再进行扩展。 我们想得到从1到6之间的一个随机数。然而,rand()产生的是从0到RANDMAX范围内的整数...

idreamo
2016/12/13
17
0
C Primer Plus 第8章 字符输入/输出和输入确认 8.6 输入确认

程序清单8.7 使用两个函数来向一个算术函数传送整数,该函数计算特定范围内所有整数的平方和。程序限制这个特定范围的上界不应该超过1000,下界不应该小于-1000。 8.6.1 分析程序 首先集中讨...

idreamo
2016/06/30
31
0
C Primer Plus 第12章 12.3 存储类和函数

函数也具有存储类。函数可以是外部的(默认情况下)或者静态的(C99增加了第三种可能性,即在第16章“C预处理器和C库"中将讨论的内联函数)。外部函数可以被其他文件中的函数调用,而静态函数...

idreamo
2016/11/19
15
0
C Primer Plus 第12章 12.9 总结

用于存储程序数据的内存可用存储时期、作用域和链接来表征。存储时期可以是静态的、自动的或者分配的。如果是静态的,内存在程序开始执行时被分配,并在程序运行时一直存在。如果是自动的,变...

idreamo
2016/12/28
25
0
关东升的《从零开始学Swift》第2版已经出版

关东升的《从零开始学Swift》第2版已经出版 大家好: 苹果2015WWDC大会发布了Swift2.0,它较之前的版本Swift1.x有很大的变化,所以我即将出版《从零开始学Swift》 《从零开始学Swift》将在《...

tony关东升
2016/02/24
0
0
C Primer Plus 第12章 12.8 关键概念

C提供了一些管理内存的模型。您应该熟悉这些不同的选项。还需要培养什么时候选用什么类型的判断力。大多数情况下,自动变量是最佳的选择。如果决定使用另一个类型,应该有一个充足的理由。通...

idreamo
2016/12/28
8
0
关东升的《从零开始学Swift》3月9日已经上架

大家一直期盼的《从零开始学Swift》于3月9日已经上架,它是关东升老师历时8个月的呕心沥血所编著,全书600多页,此本书基于Swift 2.x,通过大量案例全面介绍苹果平台的应用开发。全书共分5 部...

智捷课堂
2016/03/11
43
0
《C Primer Plus》读书笔记——存储类、链接和内存管理

背景 距离上次写读书笔记的日子已有半个月了。这段时间一直在做摄像头直立平衡车,也把《C Primer Plus》的中级部分扫了一遍。现在做赛道算法识别遇到瓶颈了,就想把读书笔记补回来。原计划是...

cugwyman
2017/02/24
0
0
关东升的《从零开始学Swift》3月9日已经上架

大家一直期盼的《从零开始学Swift》于3月9日已经上架,它是关东升老师历时8个月的呕心沥血所编著,全书600多页,此本书基于Swift 2.x,通过大量案例全面介绍苹果平台的应用开发。全书共分5 部...

tony关东升
06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

实现异步有哪些方法

有哪些方法可以实现异步呢? 方式一:java 线程池 示例: @Test public final void test_ThreadPool() throws InterruptedException { ScheduledThreadPoolExecutor scheduledThre......

黄威
今天
0
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

六库科技
今天
0
0
牛客网刷题

1. 二维数组中的查找(难度:易) 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入...

大不了敲一辈子代码
今天
0
0
linux系统的任务计划、服务管理

linux任务计划cron 在linux下,有时候要在我们不在的时候执行一项命令,或启动一个脚本,可以使用任务计划cron功能。 任务计划要用crontab命令完成 选项: -u 指定某个用户,不加-u表示当前用...

黄昏残影
昨天
0
0
设计模式:单例模式

单例模式的定义是确保某个类在任何情况下都只有一个实例,并且需要提供一个全局的访问点供调用者访问该实例的一种模式。 实现以上模式基于以下必须遵守的两点: 1.构造方法私有化 2.提供一个...

人觉非常君
昨天
0
0
《Linux Perf Master》Edition 0.4 发布

在线阅读:https://riboseyim.gitbook.io/perf 在线阅读:https://www.gitbook.com/book/riboseyim/linux-perf-master/details 百度网盘【pdf、mobi、ePub】:https://pan.baidu.com/s/1C20T......

RiboseYim
昨天
1
0
conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
昨天
1
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
昨天
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
昨天
1
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部