Который компилируется в более быстрый код:“n * 3” или “n+(n*2)”?

StackOverflow https://stackoverflow.com/questions/53757

Вопрос

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

Предполагая, что n - это либо int, либо long, и он работает на современной платформе Intel Win32.

Было бы это иначе, если бы было задействовано какое-то разыменование, то есть какое из них было бы быстрее?

long    a;
long    *pn;
long     ans;

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

Или

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

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

Это было полезно?

Решение

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

Другие советы

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

MUL EAX,3

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

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

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

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

Поскольку это легко измерить самостоятельно, почему бы этого не сделать?(Используя 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

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

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

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

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

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

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

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

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

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

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

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

:-)

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

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

Взгляните на этот ответ также хорошо.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top