正确的优化分段函数形式的多重分支代码
2006-10-13 11:07
281 查看
File: fastmif.txt
Name: 正确的优化分段函数形式的多重分支代码
Author: zyl910
Blog: http://blog.csdn.net/zyl910/
Version: V1.00
Updata: 2006-10-13
一、基本代码
有时候,我们会碰上这样的多重分支代码:
char szbuf[10];
if (score >= 90) strcpy(szbuf, "优");
elseif (score >= 80) strcpy(szbuf, "良");
elseif (score >= 60) strcpy(szbuf, "及格");
else strcpy(szbuf, "不及格");
这样的代码无疑是很低效的,怎么优化呢?
二、错误的优化
很多书上说可以根据频率分布来优化代码,比如及格的人最多时,这样编写代码:
char szbuf[10];
if (score >= 60 && score < 80) strcpy(szbuf, "及格");
elseif (score >= 80 && score < 90) strcpy(szbuf, "良");
elseif (score >= 90) strcpy(szbuf, "优");
else strcpy(szbuf, "不及格");
可以看出,这样做实际上增加了判断次数。只有在分支极多时,该优化方案才比上一个好。
三、正确的优化
现在都是做整数比较,速度非常快的,反而会因判断之后的跳转指令堵塞流水线而影响效率。所以正确的优化代码应该是这样的:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
char szbuf[10];
int i=0;
i += ( score >= 60 ); // #1
i += ( score >= 80 ); // #2
i += ( score >= 90 ); // #3
strcpy(szbuf, szlist[i]);
当score小于60时,#1、#2、#3均不成立,所以 i = i + 0 + 0 + 0 = i + 0 = 0
当score在[60,80)区间时,#1成立,所以 i = i + 1 + 0 + 0 = i + 1 = 1
当score在[80,90)区间时,#1、#2均成立,所以 i = i + 1 + 1 + 0 = i + 2 = 2
当score大于90时,#1、#2、#3均成立,所以 i = i + 1 + 1 + 1 = i + 3 = 3
最后用索引i从szlist中得到具体数据。
四、全面优化
看出来了吧,对于这种分段函数形式的多重分支代码,可以根据数据特点来优化。所以,我们还可以更进一步,将程序改成表格驱动的形式:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
const char idxlist[] = {60, 80, 90};
然后我们在idxlist表中搜索score,得到索引,再用索引从szlist得到数据。
这样无论以后的需求如何改变,我们只需要修改这两行代码就行了。
这时,可能会有人问了:如果分支极多怎么办,难道还是一个一个的比较?现在流行面向对象编程,很多时候进行的是对象比较,而对象比较的速度很慢,而现在又搞这么多比较,那不是影响效率吗?
注意我刚才说过什么——“在idxlist表中搜索score”,现在idxlist中的数据是有序的,当然用二分法查找啊!
具体说起来,由于我们在小于60(idxlist[0])时返回0、在大于等于60(idxlist[0])且小于80(idxlist[1])时返回1……所以这实际上是一个插入到有序容器算法,只不过我们只需得到插入位置(索引),并不需要进行插入。
五、总结
对于“一、基本代码”,其平均判断次数是 n/2,即 O(n)。
对于“三、正确的优化”,其平均判断次数是 n-1,即 O(n)。运算复杂度与上一个一样,但是由于它避免了跳转,所以在项目较少时,该代码的效率最高。
对于“四、全面优化”,由于它采用了二分法查找,其运算复杂度为 O(logn)。在项目很多时,它的效率最高。
Name: 正确的优化分段函数形式的多重分支代码
Author: zyl910
Blog: http://blog.csdn.net/zyl910/
Version: V1.00
Updata: 2006-10-13
一、基本代码
有时候,我们会碰上这样的多重分支代码:
char szbuf[10];
if (score >= 90) strcpy(szbuf, "优");
elseif (score >= 80) strcpy(szbuf, "良");
elseif (score >= 60) strcpy(szbuf, "及格");
else strcpy(szbuf, "不及格");
这样的代码无疑是很低效的,怎么优化呢?
二、错误的优化
很多书上说可以根据频率分布来优化代码,比如及格的人最多时,这样编写代码:
char szbuf[10];
if (score >= 60 && score < 80) strcpy(szbuf, "及格");
elseif (score >= 80 && score < 90) strcpy(szbuf, "良");
elseif (score >= 90) strcpy(szbuf, "优");
else strcpy(szbuf, "不及格");
可以看出,这样做实际上增加了判断次数。只有在分支极多时,该优化方案才比上一个好。
三、正确的优化
现在都是做整数比较,速度非常快的,反而会因判断之后的跳转指令堵塞流水线而影响效率。所以正确的优化代码应该是这样的:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
char szbuf[10];
int i=0;
i += ( score >= 60 ); // #1
i += ( score >= 80 ); // #2
i += ( score >= 90 ); // #3
strcpy(szbuf, szlist[i]);
当score小于60时,#1、#2、#3均不成立,所以 i = i + 0 + 0 + 0 = i + 0 = 0
当score在[60,80)区间时,#1成立,所以 i = i + 1 + 0 + 0 = i + 1 = 1
当score在[80,90)区间时,#1、#2均成立,所以 i = i + 1 + 1 + 0 = i + 2 = 2
当score大于90时,#1、#2、#3均成立,所以 i = i + 1 + 1 + 1 = i + 3 = 3
最后用索引i从szlist中得到具体数据。
四、全面优化
看出来了吧,对于这种分段函数形式的多重分支代码,可以根据数据特点来优化。所以,我们还可以更进一步,将程序改成表格驱动的形式:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
const char idxlist[] = {60, 80, 90};
然后我们在idxlist表中搜索score,得到索引,再用索引从szlist得到数据。
这样无论以后的需求如何改变,我们只需要修改这两行代码就行了。
这时,可能会有人问了:如果分支极多怎么办,难道还是一个一个的比较?现在流行面向对象编程,很多时候进行的是对象比较,而对象比较的速度很慢,而现在又搞这么多比较,那不是影响效率吗?
注意我刚才说过什么——“在idxlist表中搜索score”,现在idxlist中的数据是有序的,当然用二分法查找啊!
具体说起来,由于我们在小于60(idxlist[0])时返回0、在大于等于60(idxlist[0])且小于80(idxlist[1])时返回1……所以这实际上是一个插入到有序容器算法,只不过我们只需得到插入位置(索引),并不需要进行插入。
五、总结
对于“一、基本代码”,其平均判断次数是 n/2,即 O(n)。
对于“三、正确的优化”,其平均判断次数是 n-1,即 O(n)。运算复杂度与上一个一样,但是由于它避免了跳转,所以在项目较少时,该代码的效率最高。
对于“四、全面优化”,由于它采用了二分法查找,其运算复杂度为 O(logn)。在项目很多时,它的效率最高。
相关文章推荐
- 正确的优化分段函数形式的多重分支代码
- CPU与代码优化(1):用三元操作符替代if-else以降低CPU分支预测惩罚;函数13倍提速(Unity)。
- 改善代码设计 —— 优化函数的构成(Composing Methods)
- 优化分支代码——避免跳转指令堵塞流水线
- warning C4407: 在指向成员表示形式的不同指针之间进行转换,编译器可能生成不正确的代码
- 改善代码设计 —— 优化函数的构成(Composing Methods)
- 从高通caf下载内核相应分支代码的方法(非压缩打包形式,带commit的)
- 优化分支代码——避免跳转指令堵塞流水线
- 优化分支代码——避免跳转指令堵塞流水线
- 回溯法求全排列-非递归形式-代码还没优化过
- 一个非常简洁有效的判断IP地址格式是否正确的函数,c++代码
- 3.2代码结构(顺序+分支+循环)+函数
- 仅贡开发者参考代码优化之道:声明函数的十个一!
- 代码优化:饱和处理的分支优化
- Iconv是UNIX 95的iconv()函数的封装形式,它在各种字符代码体系间进行字符串转换。
- SQL Server 第四堂课,创建存储过程。存储过程是一组编译在单个执行计划中的transact-SQL语句。存储过程相当于C#函数,可以允许模块化程序设计,允许更快执行如果某操作需要大量transct-SQL代码或需要重复执行,将在创建存储过程中对其进行分析和优化。
- 优化MYSQL数据库 Monxin专用(PHP代码函数)
- 代码优化--惰性载入函数
- 利用AOP加注解的形式完成代码的优化
- 代码优化:重复代码封装成函数