【问题标题】:C for loops optimizationC for 循环优化
【发布时间】:2018-12-23 08:31:21
【问题描述】:

我正在尝试学习如何优化我的 c 代码,所以我在互联网上找到了一些文章并重新制作了我的函数,以便它可以更快地执行。当我在没有优化标志的情况下编译它时它可以工作(第二个函数比第一个函数快大约 12%),但是当我将它与 gcc -O3 一起使用时,第二个函数要慢得多(大约 50%)。你知道这是为什么吗? 感谢您的帮助。

第一个函数:

typedef struct {
    double *data;
    int rows;
    int columns;
} Matrix;

Matrix *matrixMultiplication(Matrix *a, Matrix *b) {
    if(a->columns != b->rows)
        return NULL;
    Matrix *matrix = createMatrix(a->rows, b->columns);
    set(0, matrix);
    for(int i = 0; i < matrix->rows; i++) {
        for(int j = 0; j < a->columns; j++) {
            for(int k = 0; k < b->columns; k++) {
                matrix->data[i * matrix->columns + k] += a->data[i * a->columns + j] * b->data[j * b->columns + k];
            }
        }
    }
    return matrix;
}

第二个功能:

typedef struct {
    float *data;
    unsigned int rows;
    unsigned int columns;
} Matrix_2;

unsigned int matrixMultiplication_2(Matrix_2 *a, Matrix_2 *b, Matrix_2 **c) {
    Matrix_2 *matrix;
    if(a->columns != b->rows)
        return 0;
    createMatrix_2(a->rows, b->columns, &matrix);
    set_2(0, matrix);
    for(unsigned int i = matrix->rows; i--;) {
        for(unsigned int j = a->columns; j--;) {
            for(unsigned int k = b->columns; k--;) {
                matrix->data[i * matrix->columns + k] += a->data[i * a->columns + j] * b->data[j * b->columns + k];
            }
        }
    }
    *c = matrix;
    return 1;
}

【问题讨论】:

  • 如果您想比较两种不同算法的相同功能,请确保使用相同的数据和数据结构。否则比较是没有意义的。
  • 我将它用于相同的数据,但我更改了数据结构,因为我读过我应该尽可能使用浮点数和无符号整数
  • @PatrikDobiáš 由于您使用浮点数作为一个,双数作为另一个,因此您没有使用相同的数据。
  • @你应该使用正确的类型。例如,对于索引和大小,您有 size_t。在现代系统上,使用浮点数可能会受到惩罚,因为它们可能必须转换为双精度甚至更宽的类型。
  • 尺寸有多大?

标签: c for-loop optimization


【解决方案1】:

这是因为编译器优化是基于模式识别。您的编译器知道大量典型的代码模式,并且知道如何转换它们以产生更快的代码。然而,虽然这个代码模式库非常广泛,但它是有限的。

第一个函数使用规范的for(int i = 0; i &lt; count; i++) 循环控制。你可以打赌,任何值得一提的编译器都有这样的模式,为循环控制产生接近最优的代码。

第二个函数使用了人类代码中很少见的模式。虽然我个人喜欢这种简洁的模式,但有许多程序员发现它太神秘而无法使用。显然,您的编译器没有为此提供优化器模式,因此生成的代码没有得到完全优化。


当 C 仍然只是一个高级汇编程序时,像用 for(int i = count; i--;) 替换 for(int i = 0; i &lt; count; i++) 这样的优化很有用。但是编译器优化长期以来将代码翻译变成了一个过于复杂的野兽,无法通过这些技巧进行优化。今天,大多数优化都需要在算法级别上完成。翻译级别的优化通常应该留给编译器,并通过编写编译器可以优化的规范代码来促进。

【讨论】:

  • 是的,编译器非常好。我曾经用“C”写了一些加密代码,并进行了优化编译。然后,作为一名多年的汇编程序员,我查看了生成的代码。是的,我可以保存一条指令,因为我可以使用通常保留的寄存器,可能会提高 2% 的速度。由于这段代码可以 24/7 运行几个月,这可能是值得的。一般来说,不值得付出努力,编译器在优化方面非常出色。
猜你喜欢
  • 1970-01-01
  • 2011-07-04
  • 2010-11-15
  • 2011-08-30
  • 1970-01-01
  • 2014-09-28
  • 2015-04-15
  • 1970-01-01
  • 2017-09-01
相关资源
最近更新 更多