我的任务是在C中优化特定的for循环。这是循环:
#define ARRAY_SIZE 10000
#define N_TIMES 600000
for (i = 0; i < N_TIMES; i++)
{
int j;
for (j = 0; j < ARRAY_SIZE; j++)
{
sum += array[j];
}
}
我应该使用循环展开,循环拆分和指针来加速它,但每次我尝试实现某些东西时,程序都不会返回。这是我到目前为止所尝试的内容:
for (i = 0; i < N_TIMES; i++)
{
int j,k;
for (j = 0; j < ARRAY_SIZE; j++)
{
for (k = 0; k < 100; k += 2)
{
sum += array[k];
sum += array[k + 1];
}
}
}
我不明白为什么程序现在甚至没有返回。任何帮助将不胜感激。
答案 0 :(得分:8)
第二段代码效率低下和错误,因为它增加了比原始代码更多的值。
循环展开(或者在这种情况下减少,因为你可能不想展开一万次迭代循环)将是:
// Ensure ARRAY_SIZE is a multiple of two before trying this.
for (int i = 0; i < N_TIMES; i++)
for (int j = 0; j < ARRAY_SIZE; j += 2)
sum += array[j] + array[j+1];
但是,说实话,愚蠢的编译器的时代早已过去。您通常应将此级别的微优化保留在编译器中,而您则专注于更高级别的内容,如数据结构,算法和人工分析。
最后一个相当重要。由于您将相同的数组添加到累计和中常数次,因此您只需要数组的总和,然后您可以根据需要多次添加该部分和:
int temp = 0;
for (int i = 0; i < ARRAY_SIZE; i++)
temp += array[i];
sum += temp * N_TIMES;
它仍然是O(n)
,但n
(一个而不是六十万)的乘数要低得多。 可能是gcc的疯狂优化级别-O3
可以解决这个问题,但我对此表示怀疑。在很多领域,人类大脑仍然可以超越计算机。
现在,无论如何: - )
答案 1 :(得分:3)
你的程序没有任何问题......它会返回。它只需要比第一个多50倍......
首先你有2个人:600.000 * 10.000 = 6.000.000.000次迭代。
第二个你有3个:600.000 * 10.000 * 50 = 300.000.000.000次迭代...
答案 2 :(得分:1)
循环展开不会加速循环,会减慢它们的速度。在过去,它通过减少条件评估的数量为您提供了减速。在现代,它通过杀死缓存来减慢你的速度。
此处没有明显的循环拆分用例。要分割循环,您需要在迭代中查找两个或更多明显的分组。在一段时间内,您可以将array[j]
乘以i
,而不是做外圈并声称您已将内部与外部分开,然后将外部丢弃为无用。
C数组索引语法只是定义为(一种特殊的语法)指针算法。但我猜你想要的东西是:
sum += *arrayPointer++;
取代您对j
的使用,适当地初步化。但是我怀疑你从中获得了什么。
根据评论,如果这是现实生活,那么你只需让编译器把这些东西搞清楚。