如何改进子矩阵-向量乘法c代码

问题描述 投票:0回答:1

我有用于计算通用子矩阵向量(gesubmv)乘法的 C 代码 y(rinds) = A(rinds, cinds)*x(cinds) + y(rinds),其中 rinds 和 cinds 分别是行和列(不一定排序)索引的向量。对于通用性,rinds = rindsA_data(rindsA_1:rindsA_m)cindsA_data(cindsA_1:cindsA_n).

我的代码如下:

void gesubmv(const double A_data[], const int A_size[2],
             const int rindsA_data[], int rindsA_1, int rindsA_m,
             const int cindsA_data[], int cindsA_1, int cindsA_n,
             const double x_data[], double y_data[]) {
    int i;
    int j;
    for (i = rindsA_1; i <= rindsA_m; i++) {
        int k;
        double tmp_sum;
        tmp_sum = 0.0F;
        for (j = cindsA_1; j <= cindsA_n; j++) {
            k = cindsA_data[j - 1] - 1;
            tmp_sum +=
                x_data[k] * A_data[k + (A_size[1] * (rindsA_data[i - 1] - 1))];
        }
        k = rindsA_data[i - 1] - 1;
        y_data[k] += tmp_sum;
    }
}

问题是计算 y(:) = A(:, cinds)*x(cinds) + y(:) 然后选择 y(rinds) 似乎更有效。我怀疑这可能与指令的执行方式有关 (https://godbolt.org/)。或者我可以做一些(更明显的)错误。有什么想法吗?

备选方案 y(:) = A(:, cinds)*x(cinds) + y(:) 的代码如下。

void gesubmv2(const double A_data[], const int A_size[2],
             const int cindsA_data[], int cindsA_1, int cindsA_n,
             const double x_data[], double y_data[]) {
    int i;
    int j;
    for (i = 0; i < A_size[1]; i++) {
        int k;
        double tmp_sum;
        tmp_sum = 0.0F;
        for (j = cindsA_1; j <= cindsA_n; j++) {
            k = cindsA_data[j - 1] - 1;
            tmp_sum += x_data[k] * A_data[k + (A_size[1] * i)];
        }
        y_data[i] += tmp_sum;
    }
}
c linear-algebra numerical-computing
1个回答
0
投票

您可以将 (A_size[1] * (rindsA_data[i - 1] - 1)) 表达式从 j 循环中取出。优化器可能已经在执行此操作,因此您可能看不到任何性能差异。同样,在第二个片段中,(A_size[1] * i) 不需要位于 j 循环内。如果您的优化器没有按照我的建议进行,这可能就是您看到性能差异的原因。

此外,您使用 for 语句递增 j,然后使用 j-1 作为索引,因此您可以通过在循环之前和计算 tmp_sum 之后分别放置一次 k assignmet 来节省一个操作。例如

    kk = (A_size[1] * (rindsA_data[i - 1] - 1));
    k = cindsA_data[cindsA_1 - 1] - 1;
    for (j = cindsA_1; j < cindsA_n; j++) {
        tmp_sum +=
            x_data[k] * A_data[k + kk];
        k = cindsA_data[j] - 1;
    }
    tmp_sum += x_data[k] * A_data[k + kk];
© www.soinside.com 2019 - 2024. All rights reserved.