首页 文章

gcc是否以代数方式优化c代码,如果是,则在多大程度上优化?

提问于
浏览
1

考虑下面的代码片段,显示一些简单的算术运算

int result = 0;

    result = c * (a + b) + d * (a + b) + e;

要在上面的表达式中获得结果,cpu将需要执行两次整数乘法和三次整数加法 . 但是在代数上,上面的表达式可以简化为下面的代码 .

result = (c + d) * (a + b) + e

这两个表达式在代数上是相同的,但第二个表达式只包含一个乘法和三个加法 . gcc(或其他编译器)是否能够自己进行这种简单的优化 .

现在假设编译器足够智能以进行这种简单的优化,它是否能够优化更复杂的东西,例如Trapezoidal rule(用于数值积分) . 下面的示例近似于 sin(x) 下的区域,其中 0 <= x <= pi 的步长为pi / 4(为简单起见,小) . 请假设所有文字都是运行时变量 .

#include <math.h>

// Please assume all literals are runtime variables. Have done it this way to 
// simplify the code.
double integral = 0.5 * ((sin(0) + sin(M_PI/4) * (M_PI/4 - 0) + (sin(M_PI/4) + 
    sin(M_PI/2)) * (M_PI/2 - M_PI/4) + (sin(M_PI/2) + sin(3 * M_PI/4)) * 
    (3 * M_PI/4 - M_PI/2) + (sin(3 * M_PI/4) + sin(M_PI)) * (M_PI - 3 * M_PI/4));

现在,使用梯形规则简化后,可以像这样编写上述函数 . 这大大减少了获得相同答案所需的乘法/除法的数量 .

integral = 0.5 * (1 / no_steps /* 4 in th case above*/) * 
    (M_PI - 0 /* Upper and lower limit*/) * (sin(0) + 2 * (sin(M_PI/4) +
    sin(3 * M_PI/4)) + sin(M_PI));

2 回答

  • 1

    GCC(以及大多数C编译器,就此而言)并不重构代数表达式 .

    这主要是因为就GCC和通用软件算术而言,线路

    double x = 0.5 * (4.6 + 6.7);
    double y = 0.5 * 4.6 + 0.5 * 6.7;
    
    assert(x == y); //Will probably fail!
    

    不保证评估完全相同的数字 . 如果没有这种保证,GCC无法优化这些结构 .

    此外,操作顺序可能很重要 . 例如:

    int x = y;
    int z = (y / 16) * 16;
    
    assert(x == z); //Will only be true if y is a whole multiple of 16
    

    在代数上,这两行应该是等价的,对吧?但是如果 yint ,它实际上会做的是使x等于“ y 四舍五入到16的较低整数倍” . 有时,'s intended behavior (Like if you'字节对齐) . 其他时候,这是一个错误 . 重要的是,两者都是有效的计算机代码,并且两者都可以根据具体情况使用,如果GCC围绕这些结构进行了优化,它将阻止程序员对其代码进行代理 .

  • 7

    是的,优化器,包括gcc,做这种类型的优化 . 但不一定是你引用的表达方式 . 您必须考虑可能的溢出 . 例如, (a + a) - a 可能会优化为 a . 另一个可能的优化示例是 a*a*a*atemp = a*a; (temp)*(temp)

    通过读取输出汇编代码,可以观察给定编译器是否优化引用的表达式 .

    不,默认情况下,这种类型的优化不会与浮点一起使用(除非优化器可以证明没有精度丢失) . 请参阅Are floating point operations in C associative?您可以让gcc使用 -fassociative-math 选项执行此操作 . 在你自己的危险 .

相关问题