目录
前言
选择使用不同的算法,其解决问题的效率也是截然不同的。
本文通过设计两种不同的程序针对解决给定多项式在给定点X处的值,并利用C语言中的clock()函数分别对两种程序运行时间的长短进行捕捉,从而得出解决问题的效率同算法的精妙程度有关。
(注:1.所有变量名称皆为作者随意所取,且遵循命名规则;2.文中的代码段部分为非完全程序,有需要的朋友可以自行补充;3,文中代码段由作者自己编写,若有纰漏或错误,欢迎大家指正;4.作者本人为初学者,编程水平有待提高,还望各位路过的大佬嘴下留情)
一、利用两种不同的思路解决多项式的问题
1.针对问题提出两种解决办法
下图为多项式的一般形式:
问题:设计程序通过键盘键入系数、未知数x、项数的最高次n,进而求得关于未知数x的函数值
相信大家对于多项式已经十分熟悉,在此就不再赘述。
那么如何设计程序来解决这个问题呢,下文给出两种不同的程序段来解决问题。
1.较为直白的思路:
double w1(int n,double arr[],double x)//键盘键入系数、未知数x、项数的最高次n,数组中的元素即是多项式的系数
{
int i;
double y = arr[0]; //将数组中的第一个元素赋给变量y作为初值
for( i=1 ; i<=n ; i++) //根据多项式的最大项数进行循环计算
{
y += (arr[i] * pow(x,i)); //调用数学函数pow(),其功能为得到x的i次方的值
}
return y; //返回关于x的函数值
}
这种思路较为直接,根据多项式的一般式进行一个程序化的“翻译”,而这在专业人员眼中就显得有些呆板了。
那么如何较为专业地处理这个问题呢,早在几百年前一位名叫秦久韶的数学家巧妙地利用了结合律解决了这个问题(如下图)。
每次将x作为公因子提出,由内而外进行计算,由此我们可以得到第二种思路来设计程序。
2.较为巧妙的思路:
double w2(int n,double arr[],double x) //键盘键入系数、未知数x、项数的最高次n,数组中的元素即是多项式的系数
{
int i;
double y = arr[n]; //将最高次的x的系数赋给y作为初值
for( i=n ; i>0 ;i--)
{
y = arr[i-1] + x*y; //由内向外进行计算,如若不理解,可自行代入数值进行计算
}
return y; //返回关于x的函数值
}
2.clock()函数的原理及其用法的详细解释
我们已经得到两种针对问题的不同解法,那么我们何以能说明这两种解法的孰优孰劣,孰快孰慢呢?
下面具体为大家介绍关于c语言中的clock()函数的原理及其用法,我们利用clock()函数来捕捉两种程序在运行过程中所使用的时间。
clock():捕捉从程序开始运行到clock()函数被调用时所耗费的时间。
clock tick:是一个时间单位,即“时钟打点”。
CLK_TCK:是一个常数,即机器时钟每秒所走的时钟打点数(每台机器的此常数也是不同的)。
下面为大家提供clock()函数的一个使用模板(非完全):
#include<stdio.h>
#include<time.h> //需要从时间库函数中调用clock()
//定义全局变量
clock_t start, stop;//clock_t是clock()函数返回的变量类型(start,stop为标识符)
double dur; //定义被测函数运行时间为double型变量,已秒为单位
//捕捉被测函数的运行时间
int main()
{
//不在测试范围内的准备工作及处理应写在clock()函数调用的前后
start = clock(); //开始计时(从程序开始运行到被调用)
ByUser(); //被测函数放在中间(可自定义函数部分)
stop = clock(); //停止计时(从程序开始运行到被调用)
dur = ((double)(stop - start)) / CLK_TCK; //stop与start之差即为被测函数所使用的时间(时钟打点数),将其结果强制转换为double型
//再比上时间常数(上文已给出相关概念),便得出程序运行所需秒数
printf("所用时间:%f", dur); //打印出被测函数所用时间
printf("所用时钟打点数:%f", (double)(stop - start)); //打印出被测函数所用时钟打点数
return 0;
}
二、检测程序的整体编写
1.代入具体数值对两种程序进行检测
针对问题的解决办法,以及检测解决办法的效率的工具我们已经都已准备好了,万事俱备只欠东风,下面我们整体来对捕捉被测函数运行时间的一个程序进行编写。
首先,我们拟定x=2.2,n=10,各项系数为从1至11的正整数(实验数据可自定义,此数据仅为作者随意拟定),如下图:
然后,我们尝试进行编写一个完全的程序:
#include<stdio.h>
#include<time.h> //需要从时间库函数中调用clock()
#include<math.h> //需要从数学库函数中调用pow()
#define N 10 //项数的最高次N为常数10
//定义全局变量
clock_t start, stop;
double dur;
//声明函数部分
double w1(int n, double arr[], double x);
double w2(int n, double arr[], double x);
//捕捉被测函数的运行时间
int main()
{
int i;
double arr[N]; //存储多项式的系数
for (i = 0; i < N; i++)
{
arr[i] = (double)i;
}
//对函数double w1()进行检测
start = clock();
w1(N, arr, 2.2);
stop = clock();
dur = ((double)(stop - start)) / CLK_TCK;
printf("所用时间:%f", dur);
printf("所用时钟打点数:%f", (double)(stop - start));
//对函数double w2()进行检测
start = clock();
w2(N, arr, 2.2);
stop = clock();
dur = ((double)(stop - start)) / CLK_TCK;
printf("所用时间:%f", dur);
printf("所用时钟打点数:%f", (double)(stop - start));
return 0;
}
//定义函数部分
double w1(int n, double arr[], double x)
{
int i;
double y = arr[0];
for (i = 1; i <= n; i++)
{
y += (arr[i] * pow(x, i));
}
return y;
}
double w2(int n, double arr[], double x)
{
int i;
double y = arr[n];
for (i = n; i > 0; i--)
{
y = arr[i - 1] + x * y;
}
return y;
}
2.程序的优化
当我们着手运行这段程序时,就会发现问题了,为何运行结果全为0呢?(见下图)
这是因为程序运行太快,colck()函数无法捕捉其运行时间。
在此提出解决方法:让被测函数重复运行多次次,使得测出的总的时钟打点间隔充分长,最后计算被测函数平均每次运行的时间即可!
让我们对此段程序进行部分优化(如下图)
优化后的程序:
#include<stdio.h>
#include<time.h> //需要从时间库函数中调用clock()
#include<math.h> //需要从数学库函数中调用pow()
#define N 10 //项数的最高次N为常数10
#define K 1e7 //被测函数最大重复调用次数
//定义全局变量
clock_t start, stop;
double dur;
//声明函数部分
double w1(int n, double arr[], double x);
double w2(int n, double arr[], double x);
//捕捉被测函数的运行时间
int main()
{
int i;
double arr[N]; //存储多项式的系数
for (i = 0; i < N; i++)
{
arr[i] = (double)i;
}
//对函数double w1()进行检测
start = clock();
for (i = 0; i < K; i++)
{
w1(N, arr, 2.2);
}
stop = clock();
dur = ((double)(stop - start)) / CLK_TCK;
printf("1.所用时间:%f ", dur);
printf("所用时钟打点数:%f\n", (double)(stop - start));
//对函数double w2()进行检测
start = clock();
for (i = 0; i < K; i++)
{
w2(N, arr, 2.2);
}
stop = clock();
dur = ((double)(stop - start)) / CLK_TCK;
printf("2.所用时间:%f ", dur);
printf("所用时钟打点数:%f", (double)(stop - start));
return 0;
}
//定义函数部分
double w1(int n, double arr[], double x)
{
int i;
double y = arr[0];
for (i = 1; i <= n; i++)
{
y += (arr[i] * pow(x, i));
}
return y;
}
double w2(int n, double arr[], double x)
{
int i;
double y = arr[n];
for (i = n; i > 0; i--)
{
y = arr[i - 1] + x * y;
}
return y;
}
让我们尝试运行一下吧(见下图)
优化过后,我们成功得到两种被测函数的运行时间,并且能够很清楚地得知第二种被测函数相较于第一种被测函数所使用的时间要少。
总结
通过上文的具体操作得出两种程序运行时间的长短(如若太过繁琐,可不用得出每次运行时间),从而得出两种程序在不同算法上的效率高低之分。因此,解决问题方法的效率跟算法的巧妙程度有关。