ТЕХНИКА ОПТИМИЗАЦИИ ПРОГРАММ

Выполнение алгебраических упрощений


Вычисление многих выражений можно существенно ускорить, если на этапе компиляции выполнить все возможные алгебраические упрощения. Очень показателен следующий пример, кстати, заимствованный из фирменного "хелпа" компилятора Microsoft Visual C++ (см. описание функции PreCreateWindows):

cs.y = ((cs.cy * 3) - cs.cy) / 2;

cs.x = ((cs.cx * 3) - cs.cx) / 2;

Если раскрыть скобки (помните школьный кур математики?), то получится буквально следующее:

cs.y = cs.cy;

cs.x = cs.cx;

Поскольку, оба присвоения бессмысленны (см. "Удаление лишних присвоений"), то их можно сократить. В результате мы избавляемся от двух операций умножения, двух операций деления, двух операций вычитания и двух операций  присвоения – совсем неплохой результат, правда?

К сожалению, даже современные оптимизаторы очень плохо справляются с задачей алгебраических упрощений. Так, приведенный пример не сумеет сократить ни один из них.

Ни Microsoft Visual C++, ни Borland C++, ни WATCOM не избавятся от операций деления и умножения в выражении (a=2*b/2), хотя его избыточность очевидна.

Самый продвинутый в этом плане – Microsoft Visual C++ – сокращает лишь простейшие выражения наподобие (a=3*b-b) или (a=b-b). А компиляторы Borland C++ и WATCOM могут похвастаться только тем, что автоматически вычисляют результат умножения (деления) на нуль или единицу. Т.е. следующий код "a=b*0; c=d/1" после оптимизации будет выглядеть так: "a=0; c=d".

Поэтому, всегда выполняйте все возможные алгебраические упрощения, – компилятор не собирается делать это за вас!

Заметим, что сказанное не имеет никакого отношения к константным выражениям вроде (2*3+4/2) – их "сворачивают" все три рассматриваемых компилятора.



Содержание раздела