Выполнение алгебраических упрощений
Вычисление многих выражений можно существенно ускорить, если на этапе компиляции выполнить все возможные алгебраические упрощения. Очень показателен следующий пример, кстати, заимствованный из фирменного "хелпа" компилятора 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) – их "сворачивают" все три рассматриваемых компилятора.