如何执行快速数组乘法?

时间:2013-10-31 18:53:13

标签: c arrays algorithm assembly matrix-multiplication

我有两个大小相同的数组:

A = [a1, a2, a3]
B = [b1; b2; b3]

我需要执行数组乘法才能构建以下矩阵:

            |a1|
M = A * B = |a2| * |b1 b2 b3|  //M31 * M13 ==> M33 and M13 * M31 ==> M11.  Mnk: Matrix with n lines and k columns.
            |a3|


    | a1b1 a1b2 a1b3 |
M = | a2b1 a2b2 a2b3 |
    | a3b1 a3b2 a3b3 |

哪个是执行此任务的最快算法?

更详细:我需要使用8086指令集完成这项工作,但在这里我更喜欢用C代码接收算法。

6 个答案:

答案 0 :(得分:1)

了解BLAS和LAPACK。这些都是高度优化的。除非你有理由避免使用库,否则不要重新发明轮子。这两个都有C API。

答案 1 :(得分:1)

看起来像Matrix Multiplication Algorithm 更确切地说,我认为您正在寻找efficient方式。

多重矩阵的一般方法是O(n ^ 3),但是以有效的方式,你将得到O(n ^ 2.807)。是否值得花时间实施有效的方式?我不知道,但你必须对它进行评估。

如果你只有1D数组,那么唯一的方法是双循环,在这种情况下,你看的是运行时间O(n ^ 2)。 想出来应该不会那么复杂:

for(int i = 0; i < A.length; i++)
{
    for(int j = 0; j < B.length; j++)
    {
        C[i][j] = A[i] * B[j];
    }
}

答案 2 :(得分:1)

对于这种简单的3x3情况和编译器优化,最简单的O(N^2)算法可能足够快。如果有人想要进行基准测试,那么非常欢迎您:

#include <stdio.h>

void lean_and_mean_mul(int a[3], int b[3], int out[3][3])
{
    int i, j;
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 3; j++)
        {
            out[i][j] = a[i] * b[j];
        }
    }
}

int main(void)
{
    int a[] = { 1, 2, 3 };
    int b[] = { 4, 5, 6 };
    int out[3][3];
    lean_and_mean_mul(a, b, out);
    int i, j;
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 3; j++)
        {
            printf("%d ", out[i][j]);
        }
        printf("\n");
    }
    return 0;
} 

让我们看看lean_and_mean_mul()生成的gcc -O2 -S的汇编:

    xorl    %eax, %eax         
.L2:
    movl    (%rsi), %ecx
    imull   (%rdi), %ecx
    movl    %ecx, (%rdx,%rax)
    movl    4(%rsi), %ecx
    imull   (%rdi), %ecx
    movl    %ecx, 4(%rdx,%rax)
    movl    8(%rsi), %ecx
    imull   (%rdi), %ecx
    addq    $4, %rdi
    movl    %ecx, 8(%rdx,%rax)
    addq    $12, %rax
    cmpq    $36, %rax
    jne .L2
    rep
    ret

请注意,编译器决定unroll一个循环。

使用gcc -O3编译器展开两个循环。 Code。它真的很快,因为它根本没有跳跃。

答案 3 :(得分:0)

如果您的数组很大并且想要尽可能快地将它们相乘,那么您应该查看BLAS库。

答案 4 :(得分:0)

我建议你以最简单/最简单的方式编写代码(使用2个fors和if / else),以便让编译器决定哪些优化可以/不可以完成(不要忘记设置标志到-O3)。这比通过反转矩阵访问等来尝试优化缓存/内存访问来尝试优化代码要好。如果你想进行真正的优化,找一个更好的算法,否则编码很简单。

答案 5 :(得分:0)

Wikipedia article on Matrix Multiplication告诉您所需的一切。

在这种情况下,你不会比 O(n ^ 2) 更快。

在一般情况下,矩阵乘法的最佳性能是 O(n ^ log2(7))
(大约 O(n ^ 2.8)