У вас есть две операции, которые вы хотите проводить отдельно. Первое накопление i+i
, а второе накопление i*i*i*i
.
Я предполагаю, что вы используете GCC на x86-64 с -O2
.
Если мы закомментируем total2
, сгенерированная сборка для расчета total1
будет:
movabs rdx, 999999999000000000
Умный компилятор! Это делает все вычисления во время компиляции. Таким образом, время, затраченное на это, в основном равно нулю
Если мы вместо этого закомментируем total1
, сборка для цикла для вычисления total2
будет:
.L2:
mov rdx, rax
imul rdx, rax ; i squared
add rax, 1
imul rdx, rdx ; i squared squared
add rsi, rdx ; accumulate
cmp rax, 1000000000 ; loop condition
jne .L2
Вместо того, чтобы пытаться микробенчмировать отдельные строки кода, мы можем обратиться к таблицам инструкций Агнера Фога: http://www.agner.org/optimize/instruction_tables.pdf
Предполагая, что вы используете Intel Haswell и немного распределяете порты вручную, таблицы говорят нам:
.L2: ; ports cycles latency
mov rdx, rax ; p0 0.25 1
imul rdx, rax ; p1 1 3
add rax, 1 ; p0 0.25 1
imul rdx, rdx ; p1 1 3
add rsi, rdx ; p0 0.25 1
cmp rax, 1000000000 ; p5 0.25 1
jne .L2 ; p6 1-2
Некоторые из этих инструкций могут перекрываться, поэтому это должно быть примерно 3-4 основных цикла на одну итерацию. На процессоре с частотой 3-4 ГГц для выполнения одного миллиарда итераций цикла потребуется около 1 секунды.