从软件开发来说正确性永远大于效率性。人们情愿买一辆速度慢一些的汽车,也不会去买那些速度快,但是会突然熄火或者刹车失灵的汽车。当我们在优化的同时还必须保证不会将原本的结果改变。以下是常用的优化的方法:
(注:下面的测试结果是在linux下面,使用c语言与GCC编译器。而软件效率与操作系统,语言,编译器都有关,切记每一种方法都需要自己去验证才知不知道适合自己,而不是仅仅依照别人的方法)
1. 将局域变量放在循环内和循环外定义
和
使用objdump -d 将应用软件转化为汇编,并使用vimdff进行比较,发现两个文件汇编没有什么区别,所以一般来说局域变量在循环体内或者在循环体外定义,对程序效率来说基本没有影响。当然这不包括使用动态分配内存malloc/new定义的变量。
2. 通过移位或者加法代替乘法
编译并运行后,时间差别不大,通过对其反汇编查看,两个程序汇编代码也是一样的。
但是如果是下面这种情况
让其循环0xFFFFFFF次,发现每种代码平均消耗的时间如下:
第一种 13.98s
第二种 13.16s
第三种 11.12s
通过上面的结果可以明显的发现,
如果乘的是2的指数时,编译器能够自动将其优化为移位操作,但是乘的是其他值时,可以看出最快的是转化为加法,其次是移位操作,最后才是乘法。
3. 将循环内的判断移动到循环外部
和
其平均消耗时间为0.330s 和 0.305s
通过汇编可以发现,如果循环里面加入判断条件,容易打断一个循环操作,从而无形中耗费了更多的时间,而将判断移出循环后,运行速度稍微有些增加,但是可读性及以后的维护将受到影响。
4. 将循环里面的某些不变的运算结果,通过局域变量保存起来
如:
修改为
5. 对一些精度要求不是很严格的,可以通过一些相似值进行换算
如:
修改为
6. 将一些数据先计算好,然后在存放在数组或者表格中,每次计算只需要从数组中取出。
如:
要求100以内直角三角形斜边 a^2 = x^2 + y^2;
可以定义一个数组:float a[100][100] = { {0, 0,...0},...};
如果想知道x=4,y=3的斜边,只需从数组中取出a[4][3];
此方法一旦使用,效率提升将是巨大的,但是也存在一定的局限性,如占用内存,参数范围不能太大等。
7. 其他的一些方法
从逻辑上处理,如将if/else if/.../else 或者 switch/case语句中概率最大的放在最前面。
使用缓存机制,如将上一次计算的值保留下来,如果下一次输入的参数同上一次相同的话,那么只需要还回上一次的值就可以。
使用低级语言重新对代码改写, 一般来说C# > C++/JAVA > C > 汇编, 所使用的语言越低级,其效率就越高。