2017-02-06 42 views
0

Мне нужно вычислить довольно длинные выражения, содержащие общие подвыражения. Например, рассмотрим следующие два выражения:Насколько эффективно устранение общего подвыражения компилятора?

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. Вопрос в том, узнает ли компилятор. Я обнаружил, что использование функции MuPad MATLAB 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*a, b*b, c*a и c*b?

Я использую компилятор MSVC, но я думаю, что все они делают почти то же самое.

ответ

3

Обычно компиляторы должны распознавать это и выполнять запрошенное преобразование, если вы включаете «быструю математику» (-ffast-math для gcc). Причина в том, что операции с плавающей запятой не совсем точны, и порядок оценки выражения может иметь значение.

Пример (для двойников, все константы на самом деле считаются являются результаты других операций):

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

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

Таким образом, компилятор только REORDER выражения, если вы явным образом разрешить такие преобразования.