软件安全-2.算法优化
2.1 优化基本运算
很多细微的代码都可以进行优化,其中最常见的是乘法和除法的优化.
比如以下代码:
for(i=0;i<1000;i++){
sum+=i*4;
}
如果使用移位来代替乘法运算,可以使性能提高.重写后的代码如下:
for(i=0;i<1000;i++){
sum+=(i<<2);
}
同样,向右移位相当于除于2,比如将两个数字相加之后取平均值,传统代码如下:
int mid = (hi+lo)/2
实际上,该代码可以进行优化,将两个数字的和右移,此时CPU不需要做一个除法指令,节省资源,代码如下:
int mid = (hi+lo)>>1;
求余运算也可以进行优化,比如:
a=a%8;
可以改为:
a=a&7;
该代码有助于提高性能,但如前所述,可读性变差了
此外,整数除法是整个运算中最慢的,所以应该尽可能避免.
对于连除,有时可以用乘法代替
以下是不好的代码:
int i,j,k,m;
m=i/j/k;
推荐代码:
int i,j,k,m;
m=i/(j*k);
以上操作的副作用是:有可能在乘积运算时,整数会溢出,所以只能在一定范围的除法中使用
2.2 优化流程
流程主要包括以下两类:选择和循环
1.选择结构的优化
在选择语句中,可以利用一些手段提高运行性能,如:
- 充分将可能性大的分支写在前面;
- 充分利用短路判断运算符
如下代码为根据学生的分数判断及其等级:
public String getGrade(int score) throws Exception{
String msg = null;
if(score>=60&&score<=100){
msg ="通过";
}elseif(score>=0&&score<60){
msg="未通过"
}else{
throw new Exception();
}
return msg;
}
该程序中,根据学校以往的统计经验,如果学生不能通过的概率较大,那么第二个if分支就应该调到前面去
另外,短路运算符有时也可以提高性能
如下代码:
if(条件1&&条件2)
可以将不成立概率较大的条件放在前面.
又比如:
if(条件1||条件2)
可以将成立概率较大的条件放在前面.
另外,在使用if-if结构和if-else if结构效果相同的情况下,用if-else if可以使程序减少不必要的判断
在用if判断某些值是否相等时,尽量将变量作为比较对象,如下代码:
if(a==3)
改成:
if(3==a)
这是为了消除万一程序员将==写成=造成的隐患
在选择流程的嵌套上,代码会按照顺序进行比较,匹配时就跳转到满足条件的语句执行。所以可以对嵌套可能的值依照发生的可能性进行排序,把最有可能的放在第一位,这样可以提高性能。
比如,以下代码得到一个年份的某个月份的天数:
public String getDayNumber(int year,int month{
if(year是闰年){
//得到各个月份的天数
}else{
//得到各个月份的天数
}
}
如果每个月份被输入的概率相同,那么就没有必要首先判断年份是否是闰年。因此,代码可以改为:
public String getDay/Number(int year,int month){
if(月份为2){
//判断年份是否是闰年}
//得到天数
}
else{
//得到其他各个月份的天数
}
}
综上所述,当if-else if-else语句中的分支很多时,为了减少比较的次数,明智的做法是把多分支if-else if-else语句转为嵌套if-else if-else语句。把发生频率高的情况放在一个if语句中,并且是嵌套if-else if-else语句的最外层,发生频率相对低的情况放在另一个if语句中。
2 循环的优化
循环的特点是可能会反复执行一些代码,因此,在循环中,有很多可以优化的场合,优化得好,可以大大提高系统性能。
如下代码:
Vector v;
for(int i=0;i<v.size();i++){
//一些操作
}
该代码中,循环内i<v.size();会反复执行,系统会重复计算v的大小。因此,这段代码是可以优化的
优化方法是:可以让系统只调用v.size()一次,代码如下:
Vector v;
int n = v.size();
for(int i=0;i<n;i++){
//一些操作
}
不过,如果是对集合v进行反向遍历,就没有必要进行优化了,因为此时v.size()只会调用一次。如下代码:
Vector v;
for(int i=v.size()-1;i>=0;i--){
//一些操作
}