Что компилируется в более быстрый код: «n * 3» или «n + (n * 2)»? - PullRequest
6 голосов
/ 10 сентября 2008

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

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

Было бы по-другому, если бы была задействована какая-то разыменование, то есть какая из них была бы быстрее?


long    a;
long    *pn;
long     ans;

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

Или

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

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

Ответы [ 11 ]

55 голосов
/ 10 сентября 2008

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

15 голосов
/ 10 сентября 2008

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

MUL EAX,3

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

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

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

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

10 голосов
/ 10 сентября 2008

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

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

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

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

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

4 голосов
/ 10 сентября 2008

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

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

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

1 голос
/ 20 ноября 2008

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

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

Посмотрите также этот ответ .

1 голос
/ 20 ноября 2008

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

: -)

1 голос
/ 10 сентября 2008

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

1 голос
/ 10 сентября 2008

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

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

0 голосов
/ 15 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...