编译器常见的子表达式消除效果如何?

时间:2017-02-06 12:03:31

标签: compiler-optimization

我需要计算一些包含常见子表达式的相当长的表达式。例如,请考虑以下两个表达式:

double dfdx1 = 2 * (-x2 + x1 - sin(b2)*n34 + cos(b2)*sin(c2)*n24 - cos(b2)*cos(c2)*n14 + sin(b1)*m34 - cos(b1)*sin(c1)*m24 + cos(b1)*cos(c1)*m14);

double dfdx2 = -2 * (-x2 + x1 - sin(b2)*n34 + cos(b2)*sin(c2)*n24 - cos(b2)*cos(c2)*n14 + sin(b1)*m34 - cos(b1)*sin(c1)*m24 + cos(b1)*cos(c1)*m14);

除了消除所有三角函数之外,一个明显的消除是dfdx2 = -dfdx1。问题是编译器是否会认识到这一点。我发现使用MATLAB的MuPad generate::optimize()函数没有,这让我感到很惊讶。

更一般地说,编译器是否会在下面的示例中识别出f2 = -f1

double f1 = a*a + b*b - c*a - c*b;
double f2 = c*a + c*b - a*a - b*b;

或者只是消除了a*ab*bc*ac*b这两个词?

我正在使用MSVC编译器,但我猜他们都做了几乎相同的事情。

1 个答案:

答案 0 :(得分:3)

正常情况下,编译器应该认识到这一点并执行所要求的转换,如果你启用"快速数学" (-cast-math for gcc)。原因是浮点运算并不完全精确,表达式的评估顺序可能很重要。

示例(对于双精度数,所有常量实际上都被视为其他操作的结果):

"1e100"+"1.0"-"1e100" results in 0.0 

"1e100"-"1e100"+"1.0" results in 1.0

因此,如果您明确允许这样的转换,编译器将只重新排序表达式。