ImageVerifierCode 换一换
格式:DOCX , 页数:36 ,大小:38.71KB ,
资源ID:10944767      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10944767.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(c语言优化.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

c语言优化.docx

1、c语言优化C语言常规优化策略从理论上讲,程序的优化一般分为局部优化、循环优化和全局优化三个层次。所谓局部优化,重点在于删除程序中的无用赋值,利用语言的特性对基本赋值语句优化,局部优化一般不宜过多采用,但如果程序中总是有一些无效赋值或没有引用的变量,这可能给别人造成幼稚的印象;循环优化和全局优化往往能大幅提升程序效率,因此有关的技术对于高质量的程序设计是至关重要的。本文讨论C语言程序常规优化策略,其重点在于局部优化和循环优化,包括赋值语句优化、条件语句优化、各类循环优化策略、参数传递、全局变量及宏的使用等内容,其中避免乘、除运算及浮点运算的方法是非常巧妙的。这些方法均为程序员广泛熟知并采用,这里

2、,仅仅将它们收集在一起以备大家参考。当然,各种优化策略的使用应具备时机,并遵循程序开发的基本准则。例如,对于循环优化,很多成熟的编译器均有十分全面的处理,非特别影响效率的代码段,一般不必考虑,而全局变量的采用往往会带来很多不良的副作用,一般也不宜采用。1、赋值语句优化1.1避免无用赋值在代码中,若一个变量经赋值后在后面语句的执行过程中不再引用,则这一赋值语句就称为无用赋值。且看下面杜撰的代码段int DoSmth(int x)int y, z;if (x=0)x=x;elsex=-x;y=3;z=f(x);return z;其中y=3为无用赋值语句,可以删除,而x=x语句是为了填补条件语句中条

3、件成功分支的空缺,同样是无用的赋值。在这种情况下,可以直接删除该语句,只保留一个分号作为空语句标识,如果为醒目起见,则可用null来代替。下面给出修改后的代码段int DoSmth(int x)int z;if (x=0)null;elsex=-x;z=f(x);return z;当然程序可以采用更佳的结构以驱除null语句:int DoSmth(int x)if (x0)x=-x;return f(x);但有时代码中为了保持逻辑上的完整性,或者出于理解代码的原因,有时会出现空语句,建议采用null的写法以警醒自己或其它人。在C程序中,无效的变量声明应当从程序中删除,当出现无效的变量声明时,编

4、译器一般会用“没有引用的变量”来警告你。1.2合并已知量我们要计算两点之间的距离,相应的点结构及代码的如下:typedef struct tagPointdouble x,y;Point; double Dist(Point P1, Point P2)return sqrt(P1.x-P2.x)* (P1.x-P2.x)+(P1.y-P2.y) (P1.y-P2.y);代码中, P1.x-P2.x,P1.y-P2.y均计算两次,如果我们将一次计算的结果保留下来,就可以减少相应的操作次数double Dist(Point P1, Point P2)double xDelta= P1.x-P2.x

5、;double yDelta= P1.y-P2.y;return sqrt(xDelta*xDelta+yDelta*yDelta);程序设计中还存在一种现象,为了方便,我们通常定义一系列常量,在代码中会反复引用这些常量,例如下面的代码中定义了一个圆周率常量,并在圆周长的计算中出现对它的引用#define PI3.1416double Circum(double r)return 2.0*PI*r;我们可以将常量PI与2.0的计算事先进行合并,以提高Circum函数运算效率#define PI3.1416#define TwoPI 6.2832 double Circum(double r)r

6、eturn TwoPI*r;1.3避免乘法在C程序中,由于加减运算与位运算一般比乘法快2到10倍,大部分程序员在乘法中出现2的整数次幂(2、4、8、16等)时,往往愿意将乘法操作改造成位操作以提高效率。以z=8x+y为例,多数C程序员会将其写成如下的代码z=(x3)+y;其中将x右移3位其效果等同于乘8,例如:x=19表示成二进制形式为:0000000000010011右移3位变成0000000010011000其值为152。有时,当乘数不是2的整数幂时,出于需要,我们可以根据乘数的二进制表示,将乘法改变成二进制乘法,进一步用移位和加法操作来代替乘法,例如我们要计算z=5x,由于5=4+1,其

7、中1和4均为2的整数次幂,从而z=5x可以表示成z=4x+x,相应的语句为 z=(x2)+x;这一转换通常称为二进制乘法。二进制乘法在计算机图形图象处理中经常采用,例如,对于640X480的显示屏,一般在计算机内有一块相应的显示缓冲区来保存相应的屏幕元素,我们可以用一个480行,640列的二维数组VideoBuf来指示该缓冲区。屏幕的显示是通过向缓冲区填写数据(颜色或其索引值)而实现的,假设我们要向x列、y行设置一个值color,相应的程序为:void PlotPixel(int x, int y, int color)*(VideoBuf+(long)640*y+x)=color;Video

8、Buf为一全局变量,不作为函数的参量来传递。根据二进制乘法,由640=512+128,可将PlotPixel函数改进为void PlotPixel(int x, int y, int color)/ 640y=512y+128y=(y2)+y)7*(VideoBuf+(long)(y2)+y)7)+x)=color;有两点值得指出:(1)二进制乘法会改变程序的可读性,因此,有必要在程序中用注释段说明你的思想。在改进后的PlotPixel函数中用相应的注释指出了此处二进制乘法的原理。(2)移位运算比”十”、”一”运简优先级要低,因此,在计算z=8x+y时,切不可写成z=x3)+y;其中x、y、z

9、均为整数。对于除数不是2的整数幂的情况,没有一种适当的方法将除法改进为二进制除法。通常的做法有两种:(1) 将x/y转换为x*(1.0/y),一般来说求倒数比除法快;(2) 对除数进行规范化,将其变成2的整数幂,然后进行后续处理。例如给定两个整型数组u、v,其维数均为n,我们要将u、v对应元素进行调配以生成一个新的数组w,设r为调配比例,调配公式为wi=rui+(1-r)vi其中r在0、1之间。在程序实现时,调配比例一般为百分比数值,即用户输入一个百分比Ratio,相应地r=Ratio/100。下面是两个数组进行调配的程序:void (int *w, int *u, int *v, int n

10、, int Ratio)inti;for (i=0; in; i+) wi = (Ratio*ui+(100-Ratio)*vi)/100;为了提高效率,我们可将比值Ratio规范化为0128这一范围,记R=Ratio*128/100,相应的调配公式为wi = (R*ui+(128-R)*vi)/128改进后的程序为:void (int *w, int *u, int *v, int n, int Ratio)inti;for (i=0; i7)+vi;为什么不对传入的Ratio参数直接进行限制,将其规范为0128呢?这是因为Ratio由用户输入,在用户界面的设计时,参数的意义应适合用户的习惯

11、,在本问题中,让用户输入一个百分比值当然比输入一个0128之间的数要直观得多。1.5避免浮点运算C语言中的浮点型float及双精度浮点型double运算比短整型,整型、长整型运算要慢得多,因此避免浮点运算就非常有必要。在上面避免除法运算的函数调配例子中,已经使用到了避免浮点运算的策略,百分比在通常情况下只能用一个浮点数表示,而我们将其表示为整数Ratio与100之比。1.5.1中点线算法避免浮点运算的一个经典例子为Bresenhem的画线算法,直线用两点(x1,y1), (x2,y2)刻划,且要求x1x2,直线的斜率在0, 1之间. 通常的程序为:void PlotLine(int x1, i

12、nt y1, int x2, int y2, int color)float m,y,b;/ m为斜率,b为截距int x, dx, dy; dx=x2-x1;dy=y2-y1;m=(float)dy/(float)dx;b=(float)(x2*y1-x1*y2)/(float)dx;for (x=x1; x=x2; x+)y=m*x+b;PlotPixel(x, (int)(y+0.5), color);朴素算法存在两个缺点:(1) 涉及浮点操作,画线速度有限;(2) (int)(y+0.5)为取与y最接近的整数,这将导致精度和时间的损失。Brensenham提出了一种避开浮点运算的画线算

13、法,但Brensenham的思想讨论起来比较麻烦,这里我们采用Pitteway和Van Aken等采用的中点技术。中点技术从理论上来讲与Brensenham的技术是一致的,特别是在实际画线过程中,两者产生相同的结果。同朴素画线算法一样,我们限制0m1,其它情况的画线算法可以对称地推出,m=0,1等特殊情况的处理也非常容易。假定直线左下角顶点为(x1,y1),右上角顶点为(x2,y2),对于过这两点的直线可以表示为: | x y 1 | | x1 y1 1 | =0 | x2 y2 1 |或者(y2-y1)x-(x2-x1)y+(x2y1-x1y2)=0记F(x,y)=(y2-y1)x-(x2-

14、x1)y+(x2y1-x1y2)直线F(x,y)=0将平面划分成三个部分 P2 F(x,y)0 * P1 *中点线算法的基本思想为:(1) 先画P1点;(2) 判断P1点右边或右上方的两个点E及NE中哪一个离直线更近,判断方法是确定NE和E的中点M在直线P1P2所确定的三个区域的哪一个内,这时有三种情况:(i) F(M)=0, E、NE与直线距离相等,因此可任选一个作为直线上一点,通常我们取右边的点E;(ii) F(M)0,说明M在直线下方,NE离直线更近,选 NE作为下一顶点。其中F(M)=(x1+1)dy-(y1+0.5)dx+(x1y2-x2y1), 为避开0.5,可用2F(M)作为判别

15、条件。(3) 更一般,在第p步我们得到直线上一点P(xp, yp)后,下一步(xp+1, yp+1)怎么选取呢?候选的点只能是P的右点E或右上方的点NE,原因在于直线通过x=xp时,交点(xp, yp满足yp-1/2yp=yp+1/2而xp+1=xp+1, 直线与x=xp+1的交点确定了yp+1的范围为yp-1/2yp+1yp+3/2因为yp+1=mxp+1+b=(mxp+b)+m=yp+m即yp+1只能取yp或yp+1.至于具体取E或NE,可由(2)中介绍的中点技术确定,由此得到中点线算法:void MidpointLine (int x1, int y1, int x2, int y2,

16、int color) int dx=x2-x1;int dy=y2-y1;int x, y, F;x=x1;y=y1;PlotPixel(x,y,color);while (xx2)F=2*(x+1)*dy-(2*y+1)*dx+2*(x1*y2-x2*y1);x+;if (F=0) y+;PlotPixel(x,y,color);需要指出的是:朴素画线算法及中点线算法均可以进一步改进,相应的技术可参考循环优化部分。1.5.2定点数算术若我们在计算中需要用到实数运算,但又不太关心实数的精度时,可以采用一种称之为定点数的算术。预先声明:C语言中没有定点数,它是我们人为造出来的一类数。一般地,我们

17、用一个长整数来表示一个定点数,其前24位表示整数部分,后8位表示小数部分,根据问题的需要可设计相应的定点数。这样,一个长整数类型的数就被重命名为定点数:typedef long fixed;下面讨论定点数的赋值及算术运算,我们可以将一个整型数、浮点数或一个双精度型数赋给一个定点型变量,相应的形式为fixed AssignInt (int x)return (fixed)x8; fixed AssignLong (long x) return (fixed)(x8);右移8位(除256)的理由在于:设任一定点数x的整数部分为Ix,小数部分为Fx,则x=256 (Ix+Fx/256)两个定点数乘法

18、是为了模拟它们所对应的实数乘法,设两个实数为x,y,它们对应的定点数为x,yxy=(Ix+Fx/256)(Iy+Fy/256) =IxIy+(IxFy+FxIy)/256+FxFy/(256*256)而xy的定点数表示为256IxIy+IxFy+FxIy+FxFy/256可以看到xy与xy的定点数表示之间相差256倍,这就是移8位原因所在。定点数及其定点数表示相互转化方式为fixed trans2fixed (int u, int v)/u,v为定点数x的整数部分和小数部分return (fixed)u8);*v=(int)x&255;相应地可以设计打印定点数的程序。上面对定点数算术的讨论均以

19、函数形式进行,在实际使用中,为提高效率, 可利用定点算术的思想直接进行相应的运算,例如我们要完成两个定点数17.28及9.64的一系列运算,相应的代码为void dosmth()int Ix=17, Fx=28;int Iy=9, Fy=64;fixedx, y, z1, z2;x=(fixed)Ix8)+Fx;y=(fixed)Iy8;/ z2为17.8*9.64的定点表示z=z1-z2;/ z为17.28+9.64-17.28*9.64的定点表示printf(“x=%d.%d”, (int)(x8), (int)x&255);printf(“y=%d.%d”, (int)(y8), (in

20、t)y&255);printf(“x+y-xy=%d.%d”, (int)(z8), (int)z&255);关于定点数算术还有两问题需要讨论:(1) 定点数的精度较低,只能精确表示十进制2位小数。(2) 为了保证定点数运算不发生溢出,必须要求每一个参予运算的数不能太大,这就引出了定点数最大能表示多大的数的问题。理论上来说,一个定点数最大能表示(231-1)/256,但由于加减及乘法运算可能导致溢出,因此最大的数应控制在一定范围内,例如,若x为一定点数,则要保证x*x=(231-1)/256,必须x=28938。2条件语句优化2.1多分枝条件语句优化多分枝条件语句一般采用switch语句,这样

21、的程序无论从清晰性和效率上都比原来的程序要好。例如下面的函数采用三种函数形式分别计算x在Alpha,Beta和Gamma处的值,通常的写法为:int f(int x)int y;if (x=Alpha)y=f1(x);else if (x=Beta)y=f2(x);else if (x=Gamma)y=f3(x);return y;采用switch语句可写成:int f (int x)int y;switch (x)case Alpha: y=f1(x); break;case Beta: y=f2(x); break;case Gamma: y=f3(x); break;return y;值

22、得指出的是,在多分支条件语句不能改造成语句时,我们一般采用紧缩的写法,例如我们要计算下面的分段函数值f(x)= f1(x) x=Alphaf2(x) Alpha x=Betaf3(x)Betax=Gammaf4(x)Gammax 紧缩的写法为int f(int x)int y;if (x=Alpha) y=f1(x);else if (x=Beta) y=f2(x);else if (xc(1)b+ca(2)c+ab(3)一般来说,只要有了上述三个条件,我们不必再强调a、b、c0,这些条件已经蕴含在上述三个条件中,如由(1)、(3)左、右两边分别相加化简后就可以得到a0。由此得到三角形测试问题

23、求解的第一个程序:typedefintBOOL;#define TRUE1#define FALSE0Bool IsTriangle(int a, int b, int c)if (a+bc & b+ca & c+ab)return TRUE;return FALSE;上述程序没有考虑计算溢出问题,因为a+b,b+c和c+a均可能超过一个整数的范围。为避免计算溢出,可采用长整数算术运算和比较运算,但必须考虑到机器中的长整数必须比整数的表示范围要大才行。例如在Windows 95中采用Visual C+编程时,整数和长整数均为32位,如果是这样,这种改造就没意义了。相应代码为:Bool IsTr

24、iangle(int a, int b, int c)if (long)a+(long)b(long)c & (long)b+(long)c(long)a & (long)c+(long)a(long)b)return TRUE;return FALSE;这一代码的使用是绝对安全的,唯一的问题是采用长整数算术与比较将会降低效率。如果我们要绕过长整数算术,同时又要保证代码的安全,可以对判断条件进行变换,例如,虽然三个加法会导致溢出,但只要a,b,c0,c-b,b-a,a-c却不会产生溢出,因此可将条件(1)、(2)、(3)改变为相应的代码为:Bool IsTriangle(int a, int

25、b, int c)if (a0 & b0 & c0 & ac-b & ba-c & cb-a)return TRUE;return FALSE;代码中显示地加入了a,b,c0测试,而在逻辑上由条件(4)、(5)、(6)是能蕴含这一结论的,这是否冗余的操作呢?只要注意到计算机内的算术操作受限于表示精度,同一般意义下的算术操作存在根本的差别,我们就知道这三个条件不能省略,否则可能导致减法的溢出,如a=b=-32000,整数为16位字长表示时就能明白。但在这一具体例子中,能否构造出满足条件(4)、(5)、(6)的整数a、b、c,而它们不全是正整数,有兴趣的读者可以一试。至此,我们给出了三角形测试的三个版本,应该说三个版本都不能令人完全满意。为了照顾到代码的安全性和效率,判断条件变得越来越复杂了。下面我们就给出一个更复杂的版本,可是在这两个方面都能令人愉快,从这一例子中得到的经验是:有时一个简单的

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1