当前位置:首页 > C代码优化方案
显然,for (;;)指令少,不占用寄存器,而且没有判断、跳转,比while (1)好。
6、提高CPU的并行性
(1)使用并行代码
尽可能把长的有依赖的代码链分解成几个可以在流水线执行单元中并行执行的没有依赖的代码链。很多高级语言,包括C++, 并不对产生的浮点表达式重新排序,因为那是一个相当复杂的过程。需要注意的是,重排序的代码和原来的代码在代码上一致并不等价于计算结果一致,因为浮点操作缺乏精确度。在一些情况下,这些优化可能导致意料之外的结果。幸运的是,在大部分情况下,最后结果可能只有最不重要的位(即最低位)是错误的。
不好的代码:
double a[100], sum; int i; sum = 0.0f;
for (i=0; i<100; i++) sum += a[i];
推荐的代码:
double a[100], sum1, sum2, sum3, sum4, sum; int i;
sum1 = sum2 = sum3 = sum4 = 0.0; for (i = 0; i < 100; i += 4) {
sum1 += a[i];
sum2 += a[i+1]; sum3 += a[i+2]; sum4 += a[i+3]; }
sum = (sum4+sum3)+(sum1+sum2);
要注意的是:使用4 路分解是因为这样使用了4段流水线浮点加法,浮点加法的每一个段占用一个时钟周期,保证了最大的资源利用率。
(2)避免没有必要的读写依赖
当数据保存到内存时存在读写依赖,即数据必须在正确写入后才能再次读取。虽然AMD Athlon等CPU有 加速读写依赖延迟的硬件,允许在要保存的数据被写入内存前读取出来,但是,如果避免了读写依赖并把数据保存在内部寄存器中,速度会更快。在一段很长的又互相依赖的代码链中,避免读写依赖显得尤其重要。如果读写依赖发生在操作数组时,许多编译器不能自动优化代码以避免读写依赖。所以推荐程序员手动去消除读写 依赖,举例来说,引进一个可以保存在寄存器中的临时变量。这样可以有很大的性能提升。下面一段代码是一个例子:
不好的代码:
float x[VECLEN], y[VECLEN], z[VECLEN]; 。。。。。。
for (unsigned int k = 1; k < VECLEN; k ++) {
x[k] = x[k-1] + y[k]; }
for (k = 1; k x[k] = z[k] * (y[k] - x[k-1]); } 推荐的代码: float x[VECLEN], y[VECLEN], z[VECLEN]; 。。。。。。 float t(x[0]); for (unsigned int k = 1; k < VECLEN; k ++) { t = t + y[k]; x[k] = t; } t = x[0]; for (k = 1; k <; VECLEN; k ++) { t = z[k] * (y[k] - t); x[k] = t; } 7、循环不变计算 对于一些不需要循环变量参加运算的计算任务可以把它们放到循环外面,现在许多编译器还是能自己干这件事,不过对于中间使用了变量的算式它们就不敢动了,所以很多情况下你还得自己干。对于那些在循环中调用的函数,凡是没必要执行多次的操作通通提出来,放到一个init函数里,循环前调用。另外尽量减少喂食次数,没必要的话尽量不给它传参,需要循环变量的话让它自己建立一个静态循环变量自己累加,速度会快一点。 还有就是结构体访问,东楼的经验,凡是在循环里对一个结构体的两个以上的元素执行了访问,就有必要建立中间变量了(结构这样,那C++的对象呢?想想看),看下面的例子: 旧代码: total = a->b->c[4]->aardvark + a->b->c[4]->baboon + a->b->c[4]->cheetah + a->b->c[4]->dog; 新代码: struct animals * temp = a->b->c[4]; total = temp->aardvark + temp->baboon + temp->cheetah + temp->dog; 一些老的C语言编译器不做聚合优化,而符合ANSI规范的新的编译器可以自动完成这个优化,看例子: float a, b, c, d, f, g; 。。。 a = b / c * d;
共分享92篇相关文档