在C语言中优化矩阵计算

时间:2019-05-30 07:37:17

标签: c loops for-loop matrix optimization

我正在尝试优化一些我编写的C代码,该代码将Matrix通过其转置进行乘法运算,并想知道是否有人可以看到我能做的其他事情,从而使我的方法在计算时间/时钟方面更加高效周期。

出于本示例的目的,我宁愿不更改算法以使其在数学上更有效-即在将Matrix与它的逆矩阵相乘时利用对角线属性。

我一直以一些示例代码为基础建立解决方案,然后从那里对其进行修改。到目前为止,我已经意识到我可以更改循环中事物的计算顺序,以避免不必要的计算。

未修改的示例代码:

void print_unmodified()
{
    unsigned int n = 64;
    unsigned int A[N_MAX];  // N_MAX = 64*64
    unsigned int B[N_MAX];

    // Initialising the A Matrix with values 1->64^2
    for (int i = 0; i < (n * n); i++)
    {
        A[i] = i + 1;
    }

    // Initialising the B Matrix with zeros
    for (int i = 0; i < (n * n); i++)
    {
        B[i] = 0;
    }

    // Matrix Multiplicaiton B = A*A'
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            for (int k = 0; k < n; k++)
            {
                B[i + n * j] = B[i + n * j] + A[i + n * k] * A[j + n * k];
            }
        }
    }
}

我的修改代码:

void print_modified()
{
    unsigned int n = 64;
    unsigned int A[N_MAX];
    unsigned int B[N_MAX];
    unsigned int temp = 0;

    // Initialising the A Matrix with values 1->64^2
    for (int i = 0; i < (n * n); i++)
    {
        A[i] = i + 1;
    }

    // Matrix Multiplicaiton B = A*A'
    for (int i = 0; i < n; i++)
    {   

        for (int j = 0; j < n; j++)
        {
            temp = 0;

            for (int k = 0; k < (n*n); k+=n)
            {
                temp += A[j + k] * A[i + k];
            }

            B[j + n*i] = temp;
        }
    }
}

这两种方法都以结果B矩阵结尾,所以我知道我当前的方法在数学上是正确的。

编辑:固定类型-我不想将A乘以它的倒数,而是将A与它的转置相乘。

2 个答案:

答案 0 :(得分:0)

通过在同一A循环中初始化Bfor矩阵,可以改善第一个解决方案。

n * k也会被计算两次,您可以将其存储到变量中以节省时间。

最好使用B[i + n * j] += ...而不是B[i + n * j] = B[i + n * j] + ...,因为在第一个中,B[i + n * j]被读取一次,而在第二个被读取两次。

void print_unmodified()
{
    unsigned int n = 64u;
    unsigned int A[N_MAX];
    unsigned int B[N_MAX];

    /* Initializing the A and B matrix with values 1->64^2 */
    for (int i = 0; i < (n * n); i++)
    {
        A[i] = i + 1;
        B[i] = 0u;
    }

    /* Matrix Multiplication B = A*A' */
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int index = i + n*j;
            for (int k = 0; k < n; k++)
            {
                int p = n * k;
                B[index] += A[i + p] * A[j + p];
            }
        }
    }
}

答案 1 :(得分:0)

发布的代码给出了正确的答案,矩阵 B 是另一个矩阵 A 的转置乘积,但是两个矩阵都存储在两个数组中按照主要列的顺序(或至少是OP在评论中指出的内容)。

考虑以下代码段:

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        for (int k = 0; k < n; k++) {
            B[i + n * j] = B[i + n * j] + A[i + n * k] * A[j + n * k];
        //                                  ^^^^^^^^^      ^^^^^^^^^
        }
    }
}

我们可以注意到,内部循环每次都跳过n元素遍历这些数组,这对缓存不友好。

如果我们安排循环的顺序,以使内部循环在连续的元素上进行迭代,则可以提高性能:

// Calculate the matrix B = A times A transposed. A is an n x n matrix.
// A and B are stored in plain arrays ('src' and 'dest') in column-major order 
void mult_AAT(size_t n, value_t const *src, value_t *dest)
{
    for (size_t i = 0, end = n * n; i < end; i++)
    {
        dest[i] = 0;
    }
    for (size_t k = 0; k < n; k++)         // <--
    {
        for (size_t j = 0; j < n; j++)     // <-
        {
            for (size_t i = 0; i < n; i++)
            {
                dest[j * n + i] += src[k * n + i] * src[k * n + j];
                //   ^^^^^^^^^         ^^^^^^^^^        ^^^^^^^^^     
            }
        }
    }
}

实时HERE