简体   繁体   English

C中的循环优化

[英]Loop Optimization in C

I have been tasked with optimizing a particular for loop in C. Here is the loop: 我的任务是优化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];
    }
}

I'm supposed to use loop unrolling, loop splitting, and pointers in order to speed it up, but every time I try to implement something, the program doesn't return. 我应该使用循环展开,循环拆分和指针来加速它,但每次我尝试实现某些东西时,程序都不会返回。 Here's what I've tried so far: 这是我到目前为止所尝试的:

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];
        }
    } 
}

I don't understand why the program doesn't even return now. 我不明白为什么程序现在甚至没有返回。 Any help would be appreciated. 任何帮助,将不胜感激。

That second piece of code is both inefficient and wrong, since it adds values more than the original code. 第二段代码既低效错误,因为它增加了比原始代码更多的值。

The loop unrolling (or lessening in this case since you probably don't want to unroll a ten-thousand-iteration loop) would be: 循环展开(或者在这种情况下减少,因为你可能不想展开一万次迭代循环)将是:

// 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];

But, to be honest, the days of dumb compilers has long since gone. 但是,说实话,愚蠢的编译器的时代早已过去。 You should generally leave this level of micro-optimisation up to your compiler, while you concentrate on the more high-level stuff like data structures, algorithms and human analysis. 您通常应将此级别的微优化保留在编译器中,而您则专注于更高级别的内容,如数据结构,算法和人工分析。

That last one is rather important. 最后一个是相当重要的。 Since you're adding the same array to an accumulated sum a constant number of times, you only really need the sum of the array once, then you can add that partial sum as many times as you want: 由于您将相同的数组添加到累计和中的次数相同,因此您只需要一次数组的总和然后您可以根据需要多次添加该部分和:

int temp = 0;
for (int i = 0; i < ARRAY_SIZE; i++)
    temp += array[i];
sum += temp * N_TIMES;

It's still O(n) but with a much lower multiplier on the n (one rather than six hundred thousand). 它仍然O(n)但在低得多的乘数n (一个而不是六十万)。 It may be that gcc's insane optimisation level of -O3 could work that out but I doubt it. 可能是因为gcc的疯狂优化级别-O3可以解决这个问题,但我对此表示怀疑。 The human brain can still outdo computers in a lot of areas. 人脑在很多领域仍然可以超越计算机。

For now, anyway :-) 现在,无论如何:-)

There is nothing wrong on your program... it will return. 你的程序没有任何问题...它会返回。 It is only going to take 50 times more than the first one... 它只需要比第一个多50倍...

On the first you had 2 fors: 600.000 * 10.000 = 6.000.000.000 iterations. 在第一个你有2个fors:600.000 * 10.000 = 6.000.000.000迭代。

On the second you have 3 fors: 600.000 * 10.000 * 50 = 300.000.000.000 iterations... 在第二个你有3个fors:600.000 * 10.000 * 50 = 300.000.000.000迭代......

Loop unrolling doesn't speed loops up, it slows them down. 循环展开不会加速循环,它会减慢它们的速度。 In olden times it gave you a speed bump by reducing the number of conditional evaluations. 在过去,它通过减少条件评估的数量为您提供了减速。 In modern times it slows you down by killing the cache. 在现代,它通过杀死缓存来减慢你的速度。

There's no obvious use case for loop splitting here. 这里没有明显的循环拆分用例。 To split a loop you're looking for two or more obvious groupings in the iterations. 要分割循环,您需要在迭代中查找两个或更多明显的分组。 At a stretch you could multiply array[j] by i rather than doing the outer loop and claim you've split the inner from the outer, then discarded the outer as useless. 在一段时间你可以将array[j]乘以i而不是做外循环并声称你已经将内部与外部分开,然后将外部丢弃为无用。

C array-indexing syntax is just defined as (a peculiar syntax for) pointer arithmetic. C数组索引语法只是定义为(一种特殊的语法)指针算法。 But I guess you'd want something like: 但我想你想要的东西是这样的:

sum += *arrayPointer++;

In place of your use of j , with things initialised suitably. 代替你使用j ,适当地初始化的东西。 But I doubt you'll gain anything from it. 但我怀疑你会从中获得什么。

As per the comments, if this were real life then you'd just let the compiler figure this stuff out. 根据评论,如果这是真实的生活,那么你只需让编译器弄清楚这些东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM