Время выполнения зависит от количества выполненных инструкций. Инструкции предназначены для доступа к памяти (a [i]), суммирования (sum + = a [i]) и управления циклами (I ++, ветвь).
Если количество итераций уменьшается, управление циклами и время выполнения соответственно уменьшаются. То, что вы рассматриваете, является частным случаем классического метода оптимизации кода, называемого «развертывание цикла».
Вот модифицированная версия вашего кода.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define profile(x, fn, n) {\
start = clock(); \
sum = 0; \
fn(x, n); \
time = (clock() - start) / CLOCKS_PER_SEC; \
}
#define sum2ptr(x, n) {\
for (int i = 0, j = n-1; i < j; i++, j--) { \
sum += x[i]; \
sum += x[j]; \
} \
}
#define sum1ptr(x, n) {\
for (int i = 0; i < n; i++) \
sum += x[i]; \
}
#define sum3ptr(x, n) {\
for (int i = 0; i < n; i+=4){ \
sum += x[i]; \
sum += x[i+1]; \
sum += x[i+2]; \
sum += x[i+3]; \
} \
}
#define SIZE 100000000
int main(void)
{
double start, time = 0;
int sum = 0;
int *a = (int*)malloc(SIZE * sizeof(int));
for (int i = 0; i < SIZE; i++)
a[i] = ((i * 2) + 3) % SIZE;
profile(a, sum1ptr, SIZE);
printf("%lf (regular)\n", time);
profile(a, sum2ptr, SIZE);
printf("%lf (unrolled twice)\n", time);
profile(a, sum3ptr, SIZE);
printf("%lf (unrolled 4)\n", time);
return 0;
}
Я добавил третий цикл, «развернутый» четыре раза (более классическим способом).
Скомпилировано с gcc -O
вот результаты.
0.030777 (regular)
0.016292 (unrolled twice)
0.008050 (unrolled 4)
Как видите, развертывание очень эффективно. Результаты даже лучше, чем у вас, из-за оптимизации (-O). Без флагов оптимизации получаем
0.222738 (regular)
0.174113 (unrolled twice)
0.164410 (unrolled 4)
Различия уменьшены, и, вероятно, это то, что вы добавили (но вы никогда не должны измерять производительность без оптимизации кода).