C 语言 clock() 函数,例:计算多项式值
C 语言 clock() 函数,例:计算多项式值
/**
* clock(): 捕捉从程序开始运行到 clock() 被调用时所耗费的时间。
* 这个时间单位是 clock tick, 即“时钟打点”。
* 常数 CLK_TCK: 机器时钟每秒所走的始终打点数。
* In Macintosh or C99, CLK_TCK == CLOCKS_PER_SEC
* http://www.cplusplus.com/reference/ctime/CLOCKS_PER_SEC/
*/
我把老师说的话都敲了一遍哈哈。为了测试两种算法,哪一种的效率更高,我们就需要有一个工具来记录这个算法做完这件事花费了多长时间。clock() 函数就是 C 语言所提供的工具,当然其他的语言也有,找找就能找到的。
例:写程序计算给定多项式在定点 \(x\) 处的值
\]
double f1(int n, double a[], double x)
{
int i;
double p = a[0];
for (i = 1; i <= n; i++)
p += (a[i] * pow(x, i));
return p;
}
传入阶数 n,系数放在数组 a 里面,和要计算的 x。先从这个常数项 a[0] 开始,令 p 等于 a[0],然后我们就做一个循环的累加求和的过程。每一次求和,就求和的是多项式里面的第 i 项,也就是 a[i] 乘以 x 的 i 次方。看上去这是一个特别简单的程序,但是呢,如果在正式的程序里面,你真的这么去实现这个功能的话,那会被专业的程序员严重鄙视的,我们不能这么写哈。
专业的程序员怎么处理这个问题呢?早在好几百年以前,我们有个老祖宗叫做秦九韶的,他就给出了一个非常聪明的算法。他是巧妙地利用了一下结合律,每一次把 x 当成一个公因子提出来,这样一层一层往里面提公因子。
\]
那我们在写程序计算的时候呢,这个程序是从里往外算的。这个是我们实现这个函数的标准程序
double f2(int n, double a[], double x)
{
int i;
double p = a[n];
for (i = n; i > 0; i--)
p = a[i-1] + x*p;
return p;
}
令 p 从 a[n] 开始,然后每一次用 x 乘以这个括号里面已经算出来的这个 p,然后再加上前面那一项的系数 a[i-1]。
那,凭什么说第二个函数就比第一个函数实现得要好呢?凭什么第一个函数就要被鄙视呢?因为第一个函数慢好多。到底谁快谁慢呢?不服气的话,我们要来测一下
clock() 函数
那在 C 语言里头呢,提供了一个这样的工具。C 语言提供了一个函数,叫做 clock。这个函数可以捕捉从程序开始运行,一直到这个函数被调用那个时刻所耗费的时间,但是它这个时间的单位,是 clock tick,翻译成“时钟打点“。跟它配套的,我们还有一个常数,叫 CLOCKS_PER_SEC (在 C99 以前,叫 CLK_TCK,实际上就是 clock tick 的一个缩写),给出的是这个机器时钟每秒钟走的时钟打点的数。那这个数到底等于多少呢?不同的机器可能都不一样。这两个东西配合在一起我们就可以算出来一个函数到底跑了多少秒钟。
#include <stdio.h>
#include <time.h> /* for clock() */
clock_t start, stop;
/* clock_t 是 clock() 函数返回的变量类型 */
double duration;
/* 记录被测函数运行时间,以秒为单位 */
int main()
{
/* 不在测试范围内的准备工作写在 clock() 调用之前 */
start = clock(); /* 开始计时 */
foo(); /* 把被测函数加在这里 */
stop = clock(); /* 停止计时 */
duration = ((double)(stop-start))/CLOCKS_PER_SEC;
/* 其他不在测试范围的处理写在后面,例如输出 duration 的值 */
return 0;
}
foo() 函数,就是你要测的函数。这里的命名呢涉及到历史遗留问题,在很多的例子代码中,有的变量或者函数的命名是 foo。foobar 是计算机程序领域里的术语,并无实际用途和参考意义。在计算机程序设计与计算机技术的相关文档中,术语 foobar 是一个常见的无名氏化名。
clock() 函数返回的是从这个程序开始运行,直到调用的那个时刻所耗费的时间。所以在函数开始之前调用 clock() 存到 start 这个变量里面,在函数执行结束之后,紧接着又调用一次 clock(),存到 stop 这个变量里边。那么 stop 里边存的是什么呢?就是 main() 函数开始执行,一直到这次 clock 被调用的时候,一共走了多少个 ticks。所以我们用 stop - start 就得到了 foo() 的执行过程中间一共经历了多少个 ticks,最后我们再除一下这个常数,就得到了以秒为单位的这个 duration。
下面我们就一个具体的多项式来看一下,计算 \(x\) = 1.1 处的值 \(f(1.1)\)
\]
它的系数呢,我们就让第 i 个系数就等于 i 好了。然后我们来跑一下,看看它们分别跑了多少时间。
#include <stdio.h>
#include <math.h> /* for pow() */
#include <time.h> /* for clock() */
#define MAXN 10 /* 多项式最大项数,即多项式阶数+1 */
int main()
{
int i;
double a[MAXN]; /* 存储多项式的系数 */
for (i = 0; i < MAXN; i++)
a[i] = i;
start = clock();
f1();
stop = clock();
duration = ((double)(stop-start))/CLOCKS_PER_SEC;
printf("ticks1 = %f\n", (double)(stop-start));
printf("duration1 = %f\n", duration);
start = clock();
stop = clock();
duration = ((double)(stop-start))/CLOCKS_PER_SEC;
printf("ticks2 = %f\n", (double)(stop-start));
printf("duration2 = %f\n", duration);
return 0;
}
当然你现在看起来呢,说这真是一个很傻的程序。因为没有一个很专业的程序员可以容忍说,我一段代码里头,居然有两个片段几乎是一模一样的。如果你看到这种情况,重复的情况,你应该怎么去做一个更好的处理呢?显然你应该会写一个函数去做这件事情。Anyway (无论如何),先跑一下。跑出来的结果有可能都是 0,这是因为这两个函数跑得实在是太快了,它们的运行时间都不到一个 tick,所以 clock() 函数根本捕捉不到它的区别。那这怎么办呢?如何测出不到1个tick的程序运行时间?重复
跑一次捕捉不到,跑 10 次、跑 100 次、跑 1000 次、跑 10000 次,积累一点运行时间,一直跑到间隔的时间能够被 clock() 捕捉到。最后计算单次时间的时候,你只要把总时间除以重复的次数,你就得到了这个函数一次运行的时间。
你将看到这两组数据的相对大小,应该都是差了一个数量级这个样子。所以我们就可以看到,为什么说第一个算法比较傻呢,它比第二个算法要慢了差不多一个数量级的样子。这个故事告诉我们,解决问题方法的效率,跟算法的巧妙程度有关。
再试一个多项式
给定另一个100阶多项式 \(f(x) = 1 + \sum_{i=1}^{100} \frac{x^i}{i}\),用不同方法计算 \(f(1.1)\) 并且比较一下运行时间?
C 语言 clock() 函数,例:计算多项式值的更多相关文章
- Go语言示例-函数返回多个值
Go语言中函数可以返回多个值,这和其它编程语言有很大的不同.对于有其它语言编程经验的人来说,最大的障碍不是学习这个特性,而是很难想到去使用这个特性. 简单如交换两个数值的例子: package mai ...
- C语言pow()函数的计算精度问题
编程计算 a+aa+aaa+-+aa-a(n个a)的值,n和a的值由键盘输入.例如,当n=4,a=2,表示计算2+22+222+2222的值. 程序运行结果示例: Input a,n: 2,4↙ su ...
- .net 调用R语言的函数(计算统计值pvalue 对应excel :ttest)
Pvalue 计算 项目设计pvalue计算,但是由于.net 没有类似的公式或者函数,最终决定使用.net 调用R语言 采用.net 调用r语言的公用函数 需要安装 r语言环境 https://mi ...
- Clock函数用法
clock()是C/C++中的计时函数,而与其相关的数据类型是clock_t.在MSDN中,查得对clock函数定义如下: clock_t clock(void) ; 这个函数返回从“开启这个程序进程 ...
- C语言的函数类型
C语言的函数类型与返回值类型不一致时出现,是以函数类型为标准; 而如果在java与c#语言中上述情况是编译错误的;
- CUDA学习(二)之使用clock()函数
clock()函数是C/C++中的计时函数,相关的数据类型是clock_t,使用clock函数可以计算运行某一段程序所需的时间,如下所示程序计算从10000000逐渐减一直到0所需的时间. #incl ...
- 用clock()函数计算多项式的运行时间
百度百科中定义clock():clock()是C/C++中的计时函数,而与其相关的数据类型是clock_t.在MSDN中,查得对clock函数定义如下: clock_t clock(void) ; 简 ...
- 【C语言入门教程】5.1 函数说明 与 返回值
C 语言是结构化语言,它的主要结构成分是函数.函数被作为一种构件,用以完成程序中的某个具体功能.函数允许一个程序的各个任务被分别定义和编码,使程序模块化.本章介绍 C 语言函数的设计,如何用函数分解程 ...
- clock()函数的返回值精度问题
clock()函数返回值为1毫秒,就是0.001秒.clock函数功 能: 返回处理器调用某个进程或函数所花费的时间.用 法: clock_t clock(void);说明:clock_t其实就是lo ...
随机推荐
- Haproxy状态监控配置教程
https://www.cnblogs.com/tianciliangen/p/7985881.html 方法一:在defaults段增加如下配置: stats refresh 30s #统计页面自动 ...
- MyBatis定制SQL集中特殊的处理方式
举例说明: 1.查询 姓为林的数据 LIKE 3种 Select * from sys_user where user_name like '林%' 关于结果集合多个参数传递数据 特殊字符的处理
- Hanoi双塔问题(递推)
Hanoi双塔问题 时间限制: 1 Sec 内存限制: 128 MB提交: 10 解决: 4[提交][状态][讨论版][命题人:外部导入] 题目描述 给定A,B,C三根足够长的细柱,在A柱上放有2 ...
- 关于Java中集合的讲解~
http://blog.csdn.net/zccst/article/details/5092816 comparable& Comparator 都是用来实现集合中的排序的,只是Compar ...
- 四 Mixer
Mixer在应用程序和基础架构后端之间提供通过中介层.它的设计将策略决策移出应用层,用运维人员能够控制的配置取而代之. Mixer的设计目的是改变层次之间的边界,以此降低总体复杂性.从服务代码中剔除策 ...
- STL容器迭代器失效问题讨论
STL源码剖析---迭代器失效小结 vector迭代器的几种失效的情况: .当插入(push_back)一个元素后,end操作返回的迭代器肯定失效. .当插入(push_back)一个元素后,capa ...
- SignalR推送服务在Android的实现 SignalA
SignalA是老外写的用于实现.net端推送消息至安卓端的实现,支持版本为android 2.3或以上,由于我的版本最低是2.2,所以只有把源码下下来自己改,如果你觉得太多了可自己编译成jar引用, ...
- 深入理解CPU和异构计算芯片GPU/FPGA/ASIC (下篇)
3.2.1 CPU计算能力分析 这里CPU计算能力用Intel的Haswell架构进行分析,Haswell架构上计算单元有2个FMA(fused multiply-add),每个FMA可以对256bi ...
- SQL 实现行列互换
Oracle:不过大多数是采用 oracle 数据库当中的一些便捷函数进行处理,比如 ”pivot”: MySql:目前没有找到更好的方法 题目:数据库中有一张如下所示的表,表名为sales. 年 季 ...
- Vim 配置文件===/etc/vimrc
1.替换方法 替换对应的vimrc文件,定制自己的vimrc /etc/vimrc 替换此文件: /home/lmy/.vimrc 只对当前用户有效: Ubuntu9 ...