Что компилируется для более быстрого кода: "n * 3" или "n + (n * 2)"?

Что скомпилируется для более быстрого кода: "ans = n * 3" или "ans = n + (n * 2)"?

Предполагая, что n является либо int, либо длинным, и работает на современном ящике Win32 Intel.

Разве это было бы иначе, если бы было вовлечено какое-то разыменование, т.е. какое из них было бы быстрее?

long    a;
long    *pn;
long     ans;

...
*pn = some_number;
ans = *pn * 3;

или

ans = *pn+(*pn*2);

Или, это что-то, о чем не стоит беспокоиться, поскольку оптимизация компиляторов, вероятно, будет учитывать это в любом случае?

Ответ 1

IMO такая микро-оптимизация не нужна, если вы не работаете с каким-то экзотическим компилятором. Я бы поставил читаемость на первое место.

Ответ 2

Это не имеет значения. Современные процессоры могут выполнять целочисленную инструкцию MUL за один такт или меньше, в отличие от старых процессоров, которые должны выполнять серию сдвигов и добавлять внутренне для выполнения MUL, тем самым используя несколько циклов. Я бы поспорил, что

MUL EAX,3

выполняется быстрее, чем

MOV EBX,EAX
SHL EAX,1
ADD EAX,EBX

Последний процессор, в котором такая оптимизация может быть полезной, вероятно, была 486. (да, это смещено для процессоров Intel, но, вероятно, является представителем других архитектур).

В любом случае любой разумный компилятор должен иметь возможность генерировать самый маленький/самый быстрый код. Поэтому всегда начинайте с читаемости.

Ответ 3

Как легко измерить его, почему бы не сделать этого? (Используя gcc и time из cygwin)

/* test1.c */
int main()
{
    int result = 0;
    int times = 1000000000;
    while (--times)
        result = result * 3;
    return result;
}

machine:~$ gcc -O2 test1.c -o test1
machine:~$ time ./test1.exe

real    0m0.673s
user    0m0.608s
sys     0m0.000s

Проведите тест пару раз и повторите для другого случая.

Если вы хотите заглянуть в код сборки, gcc -S -O2 test1.c

Ответ 4

Это будет зависеть от компилятора, его конфигурации и окружающего кода.

Вам не следует пытаться угадывать, "вещи" быстрее, без проведения измерений.

В общем, вы не должны беспокоиться об этом виде наномасштабной оптимизации в наши дни - это почти всегда полная нерелевантность, и если вы действительно работали в домене, где это имело значение, вы уже использовали бы профилировщик и смотрели бы на сборку языковой выход компилятора.

Ответ 5

Не сложно узнать, что делает компилятор с вашим кодом (здесь я использую DevStudio 2005). Напишите простую программу со следующим кодом:

int i = 45, j, k;
j = i * 3;
k = i + (i * 2);

Поместите точку останова на среднюю строку и запустите код с помощью отладчика. Когда точка останова запускается, щелкните правой кнопкой мыши на исходном файле и выберите "Перейти к разборке". Теперь у вас будет окно с кодом, выполняемым ЦП. В этом случае вы заметите, что последние две строки производят точно такие же инструкции, а именно: "lea eax, [ebx + ebx * 2]" (не смещение бит и добавление в этом конкретном случае). На современном процессоре IA32, вероятно, более эффективно выполнять прямое MUL, а не смещение битов из-за конвейерной природы процессора, что накладывает штраф при слишком быстром использовании модифицированного значения.

Это демонстрирует, о чем говорит аку, а именно, компиляторы достаточно умны, чтобы выбрать наилучшие инструкции для вашего кода.

Ответ 6

Это зависит от используемого вами компилятора, но, скорее всего, они переходят к одному и тому же коду.

Вы можете проверить его самостоятельно, создав небольшую тестовую программу и проверив ее разборку.

Ответ 7

Большинство компиляторов достаточно умны, чтобы разложить целочисленное умножение на ряд бит сдвигов и добавлений. Я не знаю о компиляторах Windows, но, по крайней мере, с помощью gcc вы можете заставить его выплюнуть ассемблер, и если вы посмотрите на это, вы, вероятно, увидите идентичный ассемблер для обоих способов его написания.

Ответ 8

Это не волнует. Я думаю, что есть более важные вещи для оптимизации. Сколько времени вы потратили на размышление и написание этого вопроса, а не на кодирование и тестирование самостоятельно?

: -)

Ответ 9

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

Вы задаете этот вопрос, что оптимизирующий компилятор знает больше об оптимизации, чем вы. Поэтому доверяйте компилятору. Используйте n * 3.

Посмотрите этот ответ.

Ответ 10

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

Ответ 11

Доверяйте своему компилятору оптимизацию небольших фрагментов кода. Читаемость гораздо важнее на уровне кода. Истинная оптимизация должна выходить на более высокий уровень.