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