2012-04-19 120 views
0

我想找出一个很好的循环展开乘以两个矩阵。循环展开乘以两个矩阵NxN?

例如,如果我们想总和的N×N矩阵:

void SumMatrix(int *M, int n, int *result) 
{ 
    int i,j; 

    *result = 0; 
    for (i=0; i<n; i++) 
    for (j=0; j<n; j++) 
     *result += M[j][i]; 
} 

我们可以这样做:

void SumMatrix(int *M, int n, int *result) 
{ 
    int i; 
    int size = n*n; 
    int last = size%8; 
    int acc1 = 0; 
    int acc2 = 0; 
    int *pEnd = M+size-last; 

    for (; M<pEnd; M+=8) 
    { 
     acc1 += (*M + *(M+1)) + (*(M+2) + *(M+3)); 
     acc2 += (*(M+4) + *(M+5)) + (*(M+6) + *(M+7)); 
    } 

    /* adding the last entries */ 
    while (last--) 
     acc1 += *(M++); 

    *result = acc1+acc2;   
} 

但我试图找到一个(好)的方式来乘2点矩阵,但目前没有发现。

备注:这是没有家庭作业的任务,今天我有一个考试,只是想过这个问题,我认为这对考试来说可能是一个很好的问题,不是吗?

我想感谢所有帮助

问候

罗恩

+1

取决于考试的性质。如果它特别针对低级性能优化(具有通过测量证明a)第一代码版本是显着性能瓶颈的先决条件,以及b)第二版本在实际生产环境中比第一版本运行速度快得多),那很好。如果是关于通用C编程,绝对不是。第一块代码比第二块代码更干净,易于阅读,验证和维护。 – 2012-04-19 06:53:06

+0

@PéterTörök:不,采用3个FOR循环通常乘以两个矩阵。我试图让速度更快,并且使用SUM,就像上面的代码一样。 – ron 2012-04-19 06:59:07

+0

我明白你在做什么。你了解我的意见吗?你有什么考试? – 2012-04-19 09:05:13

回答

2

大多数编译器会做的展开你(你可能需要打开一个标志,或者将其设置为优化级别 - 我相信-funroll-loops是为gcc做的)。

此外,与您的问题,这是一个二维矩阵的事实并不重要,因为你正在添加所有的数字。如果仅限于单个进程/线程,则顺序添加数字将是最快的,因为它具有最佳的高速缓存性能。您可能从SSE或向量指令中获得一些好处;再次,今天的编译器可以为你做这些这样一个简单的问题。

+0

谢谢,你有一段代码,也许我可以看看? – ron 2012-04-19 08:14:26

+0

对于使用gcc进行矢量化,使用'-ftree-vectorize'运行简单的单循环求和代码来对其进行矢量化;用'-ftree-vectorize-verbose = 2',它会在编译它向量化的循环时告诉你。 – Vanwaril 2012-04-19 16:56:21

0

看看ATLAS项目有多复杂,它提供了BLAS库的优化版本(主要基于矩阵乘法)。它不仅要考虑线程级并行性,而且要考虑内存层次结构(不仅要展开,还要缓存平铺和注册平铺,软件流水线等等)。它通常由人工编写或通过“自动调谐器”进行优化,如ATLAS。如果你想解开线程级并行性,你最好使用“平铺算法”,并在你的线程之间传播结果瓦计算。