0.前言
通常影响程序运行速度的地方,都是在执行次数最多的地方。下面介绍一些常用的技巧。
1.尽量使用整数,少用浮点数
整数运算比浮点数快得多,而在绘图程序中用到小数点的机会实在少之又少,所以这是很容易做到的技巧。
2.避免乘法与除法
乘法与除法都是相当浪费CPU运算时间的一种运算,所以在绘图程序中应尽量避免,在无法避免时,如果乘除的数目为2次方,例如2、4、8、16等,则可改用左移或右移来取代:
a2^n–>a<<n 例:a16–>a<<4
a/2^n–>a>>n 例:a/32–>a>>5
上式中2^n表示2的n次方。
3.少用求模运算
求模的运算(%)通常也是用乘除来完成的,所以速度很慢,我们也要尽量避免,当然如果除数为2的次方,那么可以改用&来替代:
a%2^n --> a&(2^n-1)
例:a%8 --> a&0x07
注意,如果除数不是2的次方,绝不能用&来替代。
4.复杂的二维计算改用查表法
所谓查表法,就是事先将一些运算结果存入表格中,然后在需要时直接取出来使用而不必再做运算。最常见的例子就是在做图形旋转时,往往会用到sin()、cos()等函数来计算角度,如果能将这些运算结果事先存于表格中,那么必能省下相当多的时间。
对于较简单的显示图形的程序,我们也可以利用查表法来避免乘法的使用。例如在320200256模式下,我们要在(x,y)的地方画出一点,那么必然要做(y*320+x)的计算,如果能将每一条起始扫描线的位置事先算出并存入表格中:
unsinged table[200];
for( i=0; i<200; i++ )
table[i] = i * 320;
那么在绘点时便可以直接使用下面的方法来取得位置:
table[y] + x;
避免了乘法运算,这就是“以空间换取时间“的做法。还有一种变形的查表法也值得一提,那就是如果在程序中有很多地方都用到了相同的运算,那么可以事先算出结果并加以储存,例如:
…
MaxSize = width * height * 3 + 200;
…
MinSize = width * height * 3 - 100;
…
则可先算出size:
size = width * height * 3;
…
MaxSize = size + 200;
…
MinSize = size - 100;
…
//注:这点和流水线的想法是一样的
5.将耗时的运算移到循环之外
通常在循环内的程序码会执行较多次,所以应减少耗时的运算,例如320200256模式政绘制一个实心的矩形时:
char far *vp = (char far *)0xA0000000L;
for( y=50; y<150; y++ )
for( x=100; x<200; x++ )
(vp+y320+x) = 0x0f;
可以改成:
char far vp = (char far )0xA0000000L;
char far p;
for( y=50; y<150; y++ )
{
p = vp+y320+100; / 将乘法移出内层循环/
for( x=100; x<200; x++ )
*(p++) = 0x0f;
}
再进一步还可以更上一层楼,将乘法完全移出循环:
char far *vp = (char far *)0xA0000000L;
char far p;
int offset = 320-(200-100);
p = vp+50320+100;
for( y=50; y<150; y++ )
{
for( x=100; x<200; x++ )
*(p++) = 0x0f;
p += offset;
}
其中offset的值正是矩形中最右边的一点到下一条扫描线最左边一点的差距值。
6.使用寄存器变量
寄存器的存取速度要比内存快,一般c/c++编译器都至少提供1~2个寄存器变量给程序使用,我们应该将使用最频繁的变量定义成寄存器变量,这样可以加快执行效率,例如:
register int i;
for( i=0; i<3000; i++ )
*(p+i) = 0x0f;
7.编译器的设置
在编译程序时,我们也可以通过某些设置来加快程序效率,例如,产生最快的执行速度的最佳化,不做堆栈溢出检查等,如果你使用tc20,那么只要在 Option菜单中选Compiler/Optimizations,然后选择底部的Fastest Code按钮便可。读者可以自行参考相关手册。