优化C for循环

时间:2016-03-14 15:19:48

标签: c linux loops optimization

到目前为止,我一直在尝试优化我的程序,但是我的目标只有不到5秒。我的代码还能改变什么呢?

#include <stdio.h>
#include <stdlib.h>

#define N_TIMES 600000
#define ARRAY_SIZE 10000

int main(void) {
    double *array = calloc(ARRAY_SIZE, sizeof(double));
    double sum = 0;
    int i, j;

    printf("CS201 - Asgmt 4 - your name\n");

    for (i = 0; i < N_TIMES; i++) {
        for (j = 0; j < ARRAY_SIZE; j = j + 20) {
            sum = sum + array[j] + array[j+1] + array[j+2] + array[j+3] +
                  array[j+4] + array[j+5] + array[j+6] + array[j+7] +
                  array[j+8] + array[j+9] + array[j+10] + array[j+11] +
                  array[j+12] + array[j+13] + array[j+14] + array[j+15] +
                  array[j+16] + array[j+17] + array[j+18] + array[j+19];
        }   
    }
}

6 个答案:

答案 0 :(得分:3)

删除所有无意义的过程。

#include <stdio.h>

int main(void) {
    printf("CS201 - Asgmt 4 - your name\n");
    return 0;
}

答案 1 :(得分:1)

让优化器为您进行优化。

我将代码粘贴到a.c

$ gcc a.c -o a
$ time ./a
CS201 - Asgmt 4 - your name

real    0m7.128s
user    0m7.032s
sys     0m0.004s
$ gcc -O2  a.c   -o a
$ time ./a
CS201 - Asgmt 4 - your name

real    0m0.001s
user    0m0.000s
sys     0m0.000s
$
除了笑话,展开是好的。

如果数据大于缓存,则切换循环可能会有所帮助。 在我的电脑上它并没有产生任何显着的差异(数据只有80kb)。

线程可能是下一步。这样你可以使用多个核心。

如果您的服务器与我的家用电脑(具有非常好的图形卡)类似,那么如果您使用它,您将获得最佳结果。 使用显卡进行计算的流行库是CUDA。

答案 2 :(得分:1)

calloc返回一个用零字节初始化的数组。考虑到您的计算机可能使用IEEE 754二进制浮点数,该数组中的所有double值均为0.0

现在,你正在做的事情基本上是重复3亿次sum = sum + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0

因此如果需要sum,我们可以优化循环:

sum = 0.0;

答案 3 :(得分:0)

使用乘法指令怎么样?

#include <stdio.h>
#include <stdlib.h>

#define N_TIMES 600000
#define ARRAY_SIZE 10000

int main (void){
    double *array = calloc(ARRAY_SIZE, sizeof(double));
    double sum = 0;
    int i, j;

    printf("CS201 - Asgmt 4 - your name\n");
    for (i = 0; i < N_TIMES; i+=N_TIMES) {
        for (j = 0; j < ARRAY_SIZE; j=j+20) {
            sum = sum + array[j] + array[j+1] + array[j+2] + array[j+3] + array[j+4] + array[j+5] + array[j+6] + array[j+7] + array[j+8] + array[j+9] + array[j+10] +   array[j+11] + array[j+12] +array[j+13] + array[j+14] + array[j+15] + array[j+16]   + array[j+17] + array[j+18] + array[j+19];
        }
        sum *=N_TIMES;
    }
    return 0;
}

答案 4 :(得分:0)

首先,让我们尝试更改算法,因为这通常可以提供最佳效果。

方法#1。 由于所有内存都是由于calloc()而分配的内存被初始化为零,并且永远不会为其分配另一个值,因此分配的数组中的每个double都将具有值0.0。因此,分配的内存中所有双精度的总和始终为0.0。

方法#2。 所有元素的总和不会从一次迭代变为下一次迭代。所以,计算一次总和然后乘以N_TIMES。

其他一些选择(如果上述情况不可接受):

方法#3。 如果每次都必须遍历循环,那么让我们帮助编译器并行执行计算,以便一次添加的结果对下一次添加的影响不小。为此,在内循环中组织添加如下...

                    tmp[0] = array[j] + array[j+1];
                    tmp[1] = array[j+2] + array[j+3];
                    tmp[2] = array[j+4] + array[j+5];
                    tmp[3] = array[j+6] + array[j+7];
                    tmp[4] = array[j+8] + array[j+9];
                    tmp[5] = array[j+10] + array[j+11];
                    tmp[6] = array[j+12] + array[j+13];
                    tmp[7] = array[j+14] + array[j+15];
                    tmp[8] = array[j+16] + array[j+17];
                    tmp[9] = array[j+18] + array[j+19];

                    tmp[0] += tmp[1];
                    tmp[2] += tmp[3];
                    tmp[4] += tmp[5];
                    tmp[6] += tmp[7];
                    tmp[8] += tmp[9];

                    tmp[0] += tmp[2];
                    tmp[4] += tmp[6];

                    tmp[0] += tmp[4];
                    sum += (tmp[8] + tmp[0]);

在我的机器上,这改善了大约17%(6.8秒到5.6秒)(gcc file.c -o file)。

方法#4。 从方法#3微调并行化。

方法#5。 如果编译器和目标机器尚未启用,则尝试启用SSE数学运算。

gcc -mfpmath=sse file.c -o file

在我的机器上,这会进一步缩短执行时间(从5.6秒到5.4)

方法#6。 同样,如果您的编译器和目标机器都支持它,请尝试编写内部循环以利用向量化 - 这样它可以同时执行多个添加。

方法#7。 打开编译器的优化标志。

gcc -mfpmath=sse -O2 file.c -o file

希望这有帮助。

答案 5 :(得分:0)

从技术上讲,代码调用未定义的行为,因为所有位0不一定是double类型的有效表示。结果未使用,但使用无效的double可能会导致触发系统定义的异常。

在具有IEEE.754浮点数的计算机上,所有位0都是0.0的表示。添加所有这些数字将产生值0.0,重复过程N_TIMES次没有任何区别。

如果您需要使用calloc()分配内存,请执行此操作,但其余计算无用:

#include <stdio.h>
#include <stdlib.h>

#define N_TIMES 600000
#define ARRAY_SIZE 10000

int main(void) {
    double *array = calloc(ARRAY_SIZE, sizeof(double));

    printf("CS201 - Asgmt 4 - your name\n");

    free(array);  // you might want to free the array for good style

    return 0;
}
相关问题