多线程解决矩阵相乘问题

多线程解决矩阵相乘问题
多线程解决矩阵相乘问题

多线程编程实现矩阵乘法

一、实验目的

通过实验,熟悉基于Win32线程库和Pthread线程库的编程环境,掌握利用Windows API和Pthread API进行多线程编程的方法,进一步加深对线程概念以及多线程编程相关事项的理解。

二、实验内容

1.在Windows操作系统上,利用Windows API编写应用程序实现矩阵乘法。

2.在Linux操作系统上,利用Pthread API编写应用程序实现矩阵乘法。

3.在上述两种环境下,实现相乘操作的两个矩阵均作为应用程序的输入参数动态生成,并输出计算结果。

4.在程序实现过程中,要求每个乘积矩阵元素的计算过程均由一个独立的线程实现。

三、实验步骤

(1)设计思路

①动态生成矩阵A,B,C并为它们分别赋值,其中C默认为0

②创建多个线程去计算矩阵C中每个元素,其中为每个线程传

入一个结构体data,它的两个数据成员为C的行号和列号

③输出矩阵C

(2)流程图

四、主要数据结构

本实验用了一个结构体类型data用于传递行号和列号五、程序运行时的初值和运行结果

①win32下

②pthread

六、实验体会:

本次实验总体感觉不难,主要就是掌握win32和pthread中线程的使用。具体的算法就是矩阵的乘法计算,较容易实现。其实,原理理解清楚,理解透,各个语言去实现都是一样的,顶多就是函数不一样而已。

七、源程序并附上注释

①用win32实现

#include

#include

#include

int row,rc,col; //矩阵A和B的行数列数

int **A; //矩阵ABC,用二维数组表示

int **B;

int **C;

struct v

{

int i; //行号

int j; //列号

};

//计算矩阵C中的某个元素

DWORD WINAPI Sum(LPVOID param)

{

struct v *DATA = (struct v*)param;//强制转换,lpvoid->struct v

for (int x=0;x

C[DATA->i][DATA->j]+=A[DATA->i][x]*B[x][DATA->j];//计算A中某行×B中某列

return 0;

}

//输出矩阵C

void output()

{

printf("C=A*B,C is:\n");

for (int x=0;x

{

for (int y=0;y

{

printf("%d ",C[x][y]); //输出C中某个元素

}

printf("\n");

}

}

int main()

{

int i,j,numThreads;

printf("input the row and col of the A matrix: \n");

scanf("%d%d",&row,&rc); //输入A矩阵长宽

A=(int **)malloc(row*sizeof(int *));

for (i=0;i

*(A+i)=(int *)malloc(rc*sizeof(int)); //为A矩阵分配空间

printf("input the elements of the A matrix: %d * %d\n",row,rc);

for (i=0;i

for (j=0;j

scanf("%d",&A[i][j]); //输入A矩阵元素

printf("input the col of the B matrix: ");

scanf("%d",&col); //输入B矩阵长度

B=(int **)malloc(rc*sizeof(int *));

for(i=0;i

*(B+i)=(int *)malloc(col*sizeof(int)); //为B矩阵分配空间

printf("input the elements of the B matrix: %d * %d\n",rc,col);

for (i=0;i

for (j=0;j

scanf("%d",&B[i][j]); //输入B矩阵元素

C=(int **)malloc(row*sizeof(int *));

for(i=0;i

*(C+i)=(int *)malloc(col*sizeof(int)); //为矩阵C分配空间

for(i=0;i

for(j=0;j

C[i][j]=0; //默认矩阵C中元素全部赋值为0

int p=0; //p用于统计线程个数

numThreads=row*col;

HANDLE *ThreadHandle=(HANDLE *)malloc(numThreads*sizeof(HANDLE));//创建线程句柄,分配空间

for(int ii=0;ii

{

for(int jj=0;jj

{

struct v*data=(struct v*) malloc (sizeof(struct v));//为结构体data分配空间

int x=ii; int y=jj;

data->i=x; //行号

data->j=y; //列号

ThreadHandle[p++]=CreateThread(NULL,0,Sum,LPVOID(data),0,NULL);//创建一个线程,并传入参数data

}

}

WaitForMultipleObjects(numThreads,ThreadHandle,TRUE,INFINITE); //等待多线程全部执行

output(); //输出矩阵C的所有元素

return 0;

}

②用pthread实现

#include

#include

#include

int row,rc,col; //矩阵A和B的行号和列号

int **A,**B,**C; //二维数组A,B,C

struct v

{

int i; //行号

int j; //列号

};

//计算矩阵C中某个元素

void *Sum(void *param)

{

int x=0;

struct v *DATA = (struct v*)param;//强制转换void*->struct v

for (x=0;x

C[DATA->i][DATA->j]+=A[DATA->i][x]*B[x][DATA->j];//计算某个元素,i行乘以j列

pthread_exit(0);

}

//输出矩阵C

void output()

{

printf("C=A*B,C is :\n");

int x,y;

for (x=0;x

{

for (y=0;y

{

printf("%d",C[x][y]);//输出C中x行y列元素

printf(" ");

}

printf("\n");

}

}

int main()

{

int i,j,numThreads;

printf("input the row and col of the A matrix: \n");//输入A矩阵长宽

scanf("%d%d",&row,&rc);

A=(int **)malloc(row*sizeof(int *));

for (i=0;i

*(A+i)=(int *)malloc(rc*sizeof(int));//为A矩阵分配空间

printf("input the elements of the A matrix: %d * %d\n",row,rc);//输入A矩阵元素for (i=0;i

for (j=0;j

scanf("%d",&A[i][j]);

printf("input the col of the B matrix: ");//输入B矩阵长度

scanf("%d",&col);

B=(int **)malloc(rc*sizeof(int *));

for(i=0;i

*(B+i)=(int *)malloc(col*sizeof(int));//为B矩阵分配空间

printf("input the elements of the B matrix: %d * %d\n",rc,col);//输入B矩阵元素

for (i=0;i

for (j=0;j

scanf("%d",&B[i][j]);

C=(int **)malloc(row*sizeof(int *)); //为矩阵C分配空间

for(i=0;i

*(C+i)=(int *)malloc(col*sizeof(int));

for(i=0;i

for(j=0;j

C[i][j]=0; //默认赋值为0

int p=0;

numThreads=row*col;

pthread_t tid;

pthread_attr_t attr;

int ii,jj;

for(ii=0;ii

{

for(jj=0;jj

{

struct v*data=(struct v*) malloc (sizeof(struct v));

//为结构体data分配内存空间

int x=ii; int y=jj;

data->i=x; //行号

data->j=y; //列号

pthread_attr_init(&attr);//初始化线程

pthread_create(&tid,&attr,Sum,(void*)data);//创建线程

pthread_join(tid,NULL); //插队,保证各个线程能在主线程运行结束前结束自己的任务

}

}

output();//输出矩阵C

return 0;

}

GPU上的矩阵乘法的设计与实现

计 算 机 系 统 应 用 https://www.360docs.net/doc/2e6330997.html, 2011 年 第20卷 第 1期 178 经验交流 Experiences Exchange GPU 上的矩阵乘法的设计与实现① 梁娟娟,任开新,郭利财,刘燕君 (中国科学技术大学 计算机科学与技术学院,合肥 230027) 摘 要: 矩阵乘法是科学计算中最基本的操作,高效实现矩阵乘法可以加速许多应用。本文使用NVIDIA 的CUDA 在GPU 上实现了一个高效的矩阵乘法。测试结果表明,在Geforce GTX 260上,本文提出的矩阵乘法的速度是理论峰值的97%,跟CUBLAS 库中的矩阵乘法相当。 关键词: 矩阵乘法;GPU ;CUDA Design and Implementation of Matrix Multiplication on GPU LIANG Juan-Juan, REN Kai-Xin, GUO Li-Cai, LIU Yan-Jun (School of Computer Science and Technology, University of Science and Technology of China, Hefei 230027, China) Abstract: Matrix multiplication is a basic operation in scientific computing. Efficient implementation of matrix multiplication can speed up many applications. In this paper, we implement an efficient matrix multiplication on GPU using NVIDIA’s CUDA. The experiment shows that our implementation is as fast as the implementation in CUBLAS, and the speed of our implementation can reach the peak speed’s 97%, on Geforce GTX260. Keywords: matrix multiplication; GPU; CUDA GPU 是一种高性能的众核处理器,可以用来加速许多应用。CUDA 是NVIDIA 公司为NVIDIA 的GPU 开发的一个并行计算架构和一门基于C 的编程语言。在CUDA 中程序可以直接操作数据而无需借助于图形系统的API 。现在已经有许多应用和典型算法使用CUDA 在GPU 上实现出来。 1 引言 矩阵乘法是科学计算中的最基本的操作,在许多领域中有广泛的应用。对于矩阵乘法的研究有几个方向。一个是研究矩阵乘法的计算复杂度,研究矩阵乘法的时间复杂度的下界,这方面的工作有strassen 算法[1]等。另外一个方向是根据不同的处理器体系结构,将经典的矩阵乘法高效的实现出来,这方面的结果体现在许多高效的BLAS 库。许多高效的BLAS 库都根据体系结构的特点高效的实现了矩阵乘法,比如GotoBLAS [2], ATLAS [3]等。Fatahalian [4]等人使 用着色语言设计了在GPU 上的矩阵乘法。CUBLAS 库是使用CUDA 实现的BLAS 库,里面包含了高性能的矩阵乘法。 本文剩下的部分组织如下,第2节介绍了CUDA 的编程模型,简单描述了CUDA 上编程的特点。第3节讨论了数据已经拷贝到显存上的矩阵乘法,首先根据矩阵分块的公式给出了一个朴素的矩阵乘法实现,分析朴素的矩阵乘法的资源利用情况,然后提出了一种新的高效的矩阵乘法。第4节讨论了大规模的矩阵乘法的设计和实现,着重讨论了数据在显存中的调度。第5节是实验结果。第6节是总结和展望。 2 CUDA 编程模型和矩阵乘法回顾 2.1 CUDA 编程模型 NVIDIA 的GPU 是由N 个多核处理器和一块显存构成的。每个多核处理器由M 个处理器核,1个指令部件,一个非常大的寄存器堆,一小块片上的共享内 ① 基金项目:国家自然科学基金(60833004);国家高技术研究发展计划(863)(2008AA010902) 收稿时间:2010-04-26;收到修改稿时间:2010-05-21

strassen矩阵相乘算法C++代码

Strassen 矩阵相乘算法代码 #include #include #include #include usingnamespace std; template class Strassen_class { public: void ADD(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize); void SUB(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize); void MUL(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize);//朴素算法实现void FillMatrix(T** MatrixA, T** MatrixB, int length);//A,B矩阵赋值 void PrintMatrix(T **MatrixA, int MatrixSize);//打印矩阵 void Strassen(int N, T **MatrixA, T **MatrixB, T **MatrixC);//Strassen算法实现 }; template void Strassen_class::ADD(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize) { for (int i = 0; i void Strassen_class::SUB(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize) { for (int i = 0; i void Strassen_class::MUL(T** MatrixA, T** MatrixB, T** MatrixResult, int MatrixSize) {

Strassen矩阵乘法

实验报告 课程名称:算法设计与分析班级:12软工一班实验成绩: 实验名称:Strassen矩阵乘法学号:1242159101 批阅教师签字: 实验编号:实验一姓名:陈双飞实验日期:2014年12月14日 指导教师:陈平组号:实验时间:时分-时分 一、实验目的 通过算法的程序实现和执行时间测试、并与理论上的结论进行对比分析,深 入理解算法时间复杂度分析中对于输入数据考虑其等价类的意义,理解算法时间 复杂度渐进性态和和增长率的概念,为后续学习和实验奠定基础,同时也学习程 序效率测试的基本思路。 二、实验内容与实验步骤 (1)了解分治的基本思想并编写算法解决Strassen矩阵乘法问题。 (2)打开一台装有MyEclipse-10.7.1的PC。 (3)把已经写好的代码在Java环境下运行并调试。 (4)记录运行结果。 三、实验环境 Windows 7家庭普通版,MyEclipse-10.7.1 四、阐述Strassen矩阵乘法 矩阵乘法是线性代数中最常见的运算之一,它在数值计算中有广泛的应用。 若A和B是2个n×n的矩阵,则它们的乘积C=AB同样是一个n×n的矩阵。A 和B的乘积矩阵C中的元素C[i,j]定义为: 若依此定义来计算A和B的乘积矩阵C,则每计算C的一个元素C[i,j],需 要做n个乘法和n-1次加法。因此,求出矩阵C的n2个元素所需的计算时间为 0(n3)。60年代末,Strassen采用了类似于在大整数乘法中用过的分治技术,将 计算2个n阶矩阵乘积所需的计算时间改进到O(nlog7)=O(n2.18)。 五、问题分析 首先,我们还是需要假设n是2的幂。将矩阵A,B和C中每一矩阵都分块 成为4个大小相等的子矩阵,每个子矩阵都是n/2×n/2的方阵。由此可将方程 C=AB重写为:

Strassen矩阵相乘算法的c++代码实现

#include #include #include using namespace std; int multiply(intn,int A[64][64],int B[64][64],int C[64][64]); int sub(int A[64][64],int B[64][64],int C[64][64],int n); int add(int A[64][64],int B[64][64],int C[64][64],int n); int main() { int n; cin>>n; inti,j; int C[64][64]; int A[64][64]; for(inti=0;i>A[i][j]; //输入A } } int B[64][64]; for(inti=0;i>B[i][j]; //输入B } } multiply(n,A,B,C); //调用递归函数 for(inti=0;i

{ cout<

Stranssen矩阵乘法

Strassen矩阵乘法 A和B都是n*n的方阵,计算C=A* B。 这个通常做法的乘法计算量是0(exp(n,3)),为了把这个计算数量级从3降到 log2(7),log2(7)略小于2.81。我们使用Strassen乘法,方法如下: 输入方阵的阶,和方阵A,B,输出C。 测试数据: Sample In (in.txt) 9 1 3 2 5 8 9 3 8 3 5 3 2 7 7 3 2 2 6 5 6 7 8 4 2 1 7 3 2 5 4 7 4 8 1 5 7 8 3 2 6 3 8 6 5 8 2 6 4 8 3 2 1 8 9 3 5 4 7 5 4 6 3 0 2 5 8 5 9 3 1 6 8 3 5 2 1 6 7 5 8 3 11 13 12 25 38 49 33 28 3 35 3 2 7 7 3 2 2 23 52 6 7 8 43 2 1 47 44 24 5 4 7 4 8 1 5 2 81 3 24 6 36 8 36 5 0 2 62 34 8 3 2 1 8 2 3 5 3 4 7 5 45 6 3 21

2 35 8 5 94 3 15 6 1 0 34 33 23 22 1 2 5 3 Sample Out (out.txt) 1031 1038 815 347 1313 346 487 337 268 1015 612 660 439 916 478 489 382 254 1166 653 506 430 1444 446 455 617 518 926 1026 763 447 1108 292 334 441 374 728 1137 992 612 1243 786 521 521 364 898 832 631 468 1391 294 344 423 396 1021 511 586 310 853 553 385 410 451 1483 814 774 483 1553 318 528 615 540 867 930 779 369 1319 488 491 357 350 Code:(strassen.cpp) #include #include #define N 65 using namespace std; void show(int n,int array[][N]) { for(int i=0;i

2x2快速矩阵乘法问题的完全求解

硕士学位论文2x2快速矩阵乘法问题的完全求解 作者姓名邓生杰 学科专业计算机软件与理论 指导教师周育人 所在学院计算机科学与工程学院论文提交日期2011年5月

Solving 2x2 Fast Matrix Multiplication Problem A Dissertation Submitted for the Degree of Master Candidate:Deng Shengjie Supervisor:Prof. Zhou Y uren South China University of Technology Guangzhou, China

分类号:TP3 学校代号:10561 学号:200820110624 华南理工大学硕士学位论文 2X2快速矩阵乘法问题的完全求解 作者姓名:邓生杰指导教师姓名、职称:周育人教授 申请学位级别:工学硕士学科专业名称:计算机软件与理论 研究方向:数据库与网络计算 论文提交日期:年月日论文答辩日期:年月日 学位授予单位:华南理工大学学位授予日期:年月日 答辩委员会成员: 主席: 委员:

华南理工大学 学位论文原创性声明 本人郑重声明:所呈交的论文是本人在导师的指导下独立进行研究所取得的研究成果。除了文中特别加以标注引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写的成果作品。对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本人完全意识到本声明的法律后果由本人承担。 作者签名:日期:年月日 学位论文版权使用授权书 本学位论文作者完全了解学校有关保留、使用学位论文的规定,即:研究生在校攻读学位期间论文工作的知识产权单位属华南理工大学。学校有权保存并向国家有关部门或机构送交论文的复印件和电子版,允许学位论文被查阅(除在保密期内的保密论文外);学校可以公布学位论文的全部或部分内容,可以允许采用影印、缩印或其它复制手段保存、汇编学位论文。本人电子文档的内容和纸质论文的内容相一致。 本学位论文属于: □保密,在年解密后适用本授权书。 □不保密,同意在校园网上发布,供校内师生和与学校有共享协议的单位浏览;同意将本人学位论文提交中国学术期刊(光盘版)电子杂志社全文出版和编入CNKI《中国知识资源总库》,传播学位论文的全部或部分内容。 (请在以上相应方框内打“√”) 作者签名:日期: 指导教师签名:日期 作者联系电话:电子邮箱: 联系地址(含邮编):

矩阵算法

矩阵及其基本算法计13 刘汝佳矩阵及其基本算法矩阵的表示矩阵的基本运算小结和应用举例一、矩阵的表示矩阵在形式上最直接的表示是一个二维数组,但是在一些特殊的场合中,我们需要引入一些特殊的方法来表示一些特殊的矩阵。在本节中,大家还将了解到以下几种表示方法: 还将了解到以下几种表示方法: 三角矩阵的压缩表示法稀疏矩阵的三元组表示法稀疏矩阵的十字链表表示法矩阵的二维数组表示法我们用二维数组很容易表示一个矩阵。加上矩阵的维数M 我们用二维数组很容易表示一个矩阵。加上矩阵的维数M 和N,我们可以定义一个我们可以定义一个TMatrix结构: 结构: struct TMatrix { int n,m; int numbers[MAXN+1][MAXN+1]; }; 这就是矩阵的二维数组表示法。怎么样,容易吧?这就是矩阵的二维数组表示法。怎么样,容易吧?三角矩阵的压缩表示(1) 三角矩阵的压缩表示N阶上三角矩阵,对称矩阵和反对称矩阵都只需要储存主对角线以上的共(N+1)*N/2个元素。N+1)*N/2个元素。因此,我们可以用一个大小为( 因此,我们可以用一个大小为(N+1)*N/2 的一维数组来表示。不过,我们需要一个公式,把每个元素原来的位置(i,j)映射到一维数组的下标k 原来的位置(i,j)映射到一维数组的下标k。三角矩阵的压缩表示(2) 三角矩阵的压缩表示我们从上到下,从左到右地储存各个元素,如下图:?a11 a12 a13 a14 ? ? a a a ? 22 23 24 ? ? ? a33 a34 ? ? ? a44 ? ? i ?1 l =1 ?a1 a2 a3 a4 ? ? a a a ? 5 6 7 ? ? ? a8 a9 ? ? ? a10 ? ? Aij前面的数的个数为:(n ? l + 1) + ( j ? 1) ∑ 计算得: 计算得: 1 k = (2n ? i + 2)(i ? 1) + j 2 稀疏矩阵在前面的二维数组表示法中,我们表示一个N*M的矩阵需要N*M个内存单元。一个N*M的矩阵需要N*M个内存单元。如果已知矩阵中存在着大量的0 如果已知矩阵中存在着大量的0元素,那么这种表示方法是很浪费空间的。由于非零元素的个数L 由于非零元素的个数L十分有限,我们可以只储存下这L 以只储存下这L个元素的位置和大小,占用的空间便会少得多。稀疏矩阵的三元组表示法显然,表示稀疏矩阵最直接的方法就是仅记录下非零元素的个数L和这L 仅记录下非零元素的个数L和这L个元素的位置(row,col)和大小(value),的位置(row,col)和大小(value),即下面这个结构:struct TMatrix2 { int l; int row[MAXL],col[MAXL],value[MAXL]; }; 稀疏矩阵的十字链表表示(1) 稀疏矩阵的十字链表表示三元组表示法比较好的解决了稀疏矩阵的空间存储问题,却忽视了稀疏矩阵可能进行了一些基本操作。考虑两个稀疏矩阵A考虑两个稀疏矩阵A和B相加的问题。对于运算结果矩阵C来说,可能会因为正负抵消而产生出很多新的零元素和非零元素,导致三元组需要进行一些插入和删除操作。当这些操作很频繁的时候,程序的速度会明显变慢。在某些特定情况下,我们需要对元素进行检索,由于三元组的元素之间联系并不紧密,所以检索很不方便。稀疏矩阵的十字链表表示(2) 稀疏矩阵的十字链表表示为了加强同一行和同一列之间元素的联系,我们把每一行分别做成一个链表,把每一列也分别做成一个链表。通过对链表的遍历,我们可以很方便的按顺序访问到某一特定行或列的所有元素。插入和删除操作也很方便。这样,我们了建立一种十字型的链表结构,每个结点有上,下,左,右四个指针和自身的位置坐标,大小共7 置坐标,大小共7个域。稀疏矩阵的十字链表表示(3) 稀疏矩阵的十字链表表示结点类型如下定义:struct Tnode { int row, col; int value; Tnode *left, *right, *up, *down; }; row,col分别为该非零元素的位置,value为它的值。row,col分别为该非零元素的位置,value为它的值。left,right,up,down 分别为指向四个方向的后继元素。left,right,up,down分别为指向四个方向的后继元素。稀疏矩阵的十字链表表示(4) 稀疏矩阵的十字链表表示为了方便的找到每一个包含非零元素的行和列,我们把所有行串在一起,组成一个行链表,把所有列也串在一起,组成一个列链表。像这样:struct TRow { int RowNo; TNode * firstnode; }; struct TCol { int ColNo; TNode * firstnode; }; 矩阵表示方法小结矩阵的表示方法和应用是分不开的。我们衡量一种表示方法的优劣,需要从不同的角度进行分析。适用范围空间需求量基本操作的时间消耗实现的难易程度以上几种方法都在某些方面表现良好而其他方面不够理想,因此我们

矩阵乘法(分治法)

算法设计与分析实验报告

二、模型拟制、算法设计和正确性证明: 设A和B是两个n*n阶矩阵,求他们两的成绩矩阵C。这里假设n是2的幂次方; A和B是两个n*n的矩阵,他们的乘积C=AB也是一个n*n的矩阵,矩阵C中的元素C[i][j] 定义为C[i][j]= ,则每计算一个C[i][j],需要做n次乘法和n-1次加法。 因此计算C的n2个元素需要n3次乘法和n3- n2次加法。因此,所需的时间复杂度是O(n3)。 但是使用分治法可以改进算法的时间复杂度。这里,假设n是2的幂。将矩阵A,B,C中每一矩阵都分成4个大小相等的子矩阵,每个子矩阵是(n/2)*(n/2)的方阵。由此,可将方阵C=AB重写为 因此可得: C11=A11B11+A12B21 C12=A11B12+A12B22 C21=A21B11+A22B22 C22=A21B12+A22B22 这样就将2个n阶矩阵的乘积变成计算8个n/2阶矩阵的乘积和4个n/2阶矩阵的加法。 当n=1时,2个1阶方阵的乘积可直接算出,只需要做一次乘法。当子矩阵阶n>1时,为求两个子矩阵的乘积,可继续对两个子矩阵分块,直到子矩阵的阶为1。由此,便产生了分治降阶的递归算法。 但是这个算法并没有降低算法的时间复杂度。由strassen矩阵乘法, M1=A11(B12-B22) M2=(A11+A12)B22 M3=(A21+A22)B11 M4=A22(B21-B11) M5=(A11+A22)(B11+B22) M6=(A12-A22)(B21+B22) M7=(A11-A21)(B11+B12)

四、程序实现和测试过程:程序测试过程(1) 测试过程(2)

计算矩阵连乘积

计算矩阵连乘积 问题描述 在科学计算中经常要计算矩阵的乘积。矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。若A是一个p×q的矩阵,B是一个q×r的矩阵,则其乘积C=AB是一个p ×r的矩阵。其标准计算公式为: 由该公式知计算C=AB总共需要pqr次的数乘。 现在的问题是,给定n个矩阵{A1,A2,…,A n}。其中A i与A i+1是可乘的,i=1,2,…,n-1。要求计算出这n个矩阵的连乘积A1A2…A n。 由于矩阵乘法满足结合律,故连乘积的计算可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序已完全确定,也就是说该连乘积已完全加括号,则我们可以通过反复调用两个矩阵相乘的标准算法计算出矩阵连乘积。完全加括号的矩阵连乘积可递归地定义为: 1. 单个矩阵是完全加括号的; 2. 若矩阵连乘积A是完全加括号的,则A可表示为两个完全加括号的矩阵 连乘积B和C的乘积并加括号,即A=(BC)。 例如,矩阵连乘积A1A2A3 A4可以有以下5种不同的完全加括号方式: (A1(A2(A3A4))), (A1((A2A3)A4)), ((A1A2)(A3A4)), ((A1(A2A3))A4), (((A1A2)A3)A4)。 每一种完全加括号方式对应于一种矩阵连乘积的计算次序,而这种计算次序与计算矩阵连乘积的计算量有着密切的关系。 为了说明在计算矩阵连乘积时加括号方式对整个计算量的影响,我们来看一个计算3个矩阵{A1,A2,A3}的连乘积的例子。设这3个矩阵的维数分别为10×100,100×5和5×50。若按第一种加括号方式((A1A2)A3)来计算,总共需要10×100×5+10×5×50=7500次的数乘。若按第二种加括号方式(A1(A2A3))来计算,则需要的数乘次数为100×5×50+10

并行处理实验报告:用MPI实现的矩阵乘法的加速比分析(推荐文档)

华中科技大学 课程名称并行处理 实验名称矩阵乘法的实现及加速比分析考生姓名李佩佩 考生学号 M201372734 系、年级计算机软件与理论2013级类别硕士研究生 考试日期 2014年1月3日

一. 实验目的 1) 学会如何使用集群 2) 掌握怎么用并行或分布式的方式编程 3) 掌握如何以并行的角度分析一个特定的问题 二. 实验环境 1) 硬件环境:4核CPU、2GB内存计算机; 2) 软件环境:Windows XP、MPICH2、VS2010、Xmanager Enterprise3; 3) 集群登录方式:通过远程桌面连接211.69.198.2,用户名:pppusr,密码:AE2Q3P0。 三. 实验内容 1. 实验代码 编写四个.c文件,分别为DenseMulMatrixMPI.c、DenseMulMatrixSerial.c、SparseMulMatrixMPI.c和SparseMulMatrixSerial.c,用于比较并行和串行矩阵乘法的加速比,以及稀疏矩阵和稠密矩阵的加速比。这里需要说明一下,一开始的时候我是把串、并行放在一个程序中,那么就只有两个.c文件DenseMulMatrix.c 和SparseMulMatrix.c,把串行计算矩阵乘的部分放到了主进程中,即procsID=0的进程,但是结果发现执行完串行后,再执行并行就特别的慢。另外,对于稀疏矩阵的处理方面可能不太好,在生成稀疏矩阵的过程中非0元素位置的生成做到了随机化,但是在进行稀疏矩阵乘法时没有对矩阵压缩,所以跟稠密矩阵乘法在计算时间上没多大区别。 方阵A和B的初始值是利用rand()和srand()函数随机生成的。根据稀疏矩阵和稠密矩阵的定义,对于稀疏矩阵和稠密矩阵的初始化方法InitMatrix(int *M,int *N,int len)会有所不同。这里需要说明一下,一开始对于矩阵A和B的初始化是两次调用InitMatrix(int *M ,int len),生成A和B矩阵,但是随后我发现,由于两次调用方法InitMatrix的时间间隔非常短,又由于srand()函数的特点,导致生成的矩阵A和B完全一样;然后,我就在两次调用之间加入了语句“Sleep(1000);”,加入头文件“#include ”,这样生成的A、B矩阵就不一样了,但很快问题又出现了,在Xshell中不能识别头文件“#include ”。所以,最后决定用下面的方法生成矩阵A和B,B是A的转置。 //稠密矩阵的生成方法 void InitMatrix(int *M,int *N,int len) { srand((unsigned)time( NULL)); for(i=0; i < len*len; i++)

实验二Strassen矩阵乘法

实验2 Strassen矩阵乘法 一、 实验目的 1.理解Strassen矩阵乘法的分治思想 Strassen矩阵乘法的分治法设计模式是:半分+混合 2.改进Strassen矩阵乘法对内存的需求 若按Strassen矩阵乘法的直接表述实现,则空间复杂度将是O(3n2),本实验将试图改进这个方面。 3.Strassen矩阵乘法的性能问题 改进Strassen矩阵乘法的内存需求,并不一定能改进Strassen矩阵乘法的效率,本实验将试图测试一些较大规模(n>=1024)的n阶方阵的Strassen矩阵乘,探讨其效率问题。 二、 实验环境 C/C++编程环境或任何编程语言环境 三、 实验内容 1. Strassen矩阵乘法描述 尽管Strassen矩阵乘法的实用价值在当今的多核计算环境下可能不是那么显著,但其理论价值仍值得我们研究。Strassen矩阵乘法体现了一类重要的分治算法设计模式,即半分+混合,同样具有这种算法设计模式的是FFT(Fast Fourier Transform)-“由于FFT这个卓越算法在实践上的重要意义,有些人把它看作是有史以来人们发明的最重要的算法之一。”[1]

Strassen 矩阵乘法的基本思想,可由下述矩阵乘法概括: 输入:两个n=2k 维方阵A 和B (若A 和B 的维度不是2k ,则通过增加元素为0的行和列,以使A 和B 均为2k 维的方阵) 输出:n 维方阵 C (1) 1+41+443-11+24134.12-43+4113.123-11+224.3424.1314.11.2412.4-434 4+=A B =A B =A B =A B =A B M =A B M =A M M B M M M (2) 为方便表示,这里采用与书本不同的下标表示法,如对于1个n/2维矩阵 14.14M ,下标14.14表示其由两个矩阵A 1+4和B 1+4乘积而成,A 1+4表示A1+A4, 同理B 1+4表示B1+B4,同理12.4M 表示A1+2与B4的乘积。采用这种表示法,目的是为了记住每个M 矩阵是由A 和B 的哪一个或两个子矩阵得到的,从而方便后面的内存分配设计。 1)第一步:半分(半分指维度,若指面积也许应叫1/4分) 将A 和B 两个n 维方阵各分解为4份,每份n/2维,即A1,A2,A3,A4和B1,B2,B3,B4。 2)第二步:混合 将维度为n/2的7个子矩阵的“混合”(加减运算混合法),存入维度为n 的结果矩阵C 的4个位置中,即C 的4个n/2维的子矩阵依次是: = 4.13124.14.1444312.M C -+M M M + 1.24142 2.M M C =+ 34.1433.1M M C =+ (3)

算法之大整数乘法

大整数乘法 通常,在分析一个算法的计算复杂性时,都将加法和乘法运算当作是基本运算来处理,即将执行一次加法或乘法运算所需的计算时间当作一个仅取决于计算机硬件处理速度的常数。 这个假定仅在计算机硬件能对参加运算的整数直接表示和处理时才是合理的。然而大整数的算术运算。 请设计一个有效的算法,可以进行两个n位大整数的乘法运算。 大整数的乘法 问题描述 参考解答 设X和Y都是n位的二进制整数,现在要计算它们的乘积XY。我们可以用小学所学的方法来设计一个计算乘积XY的算法,但是这样做计算步骤太多,显得效率较低。如果将每2个1位数的乘法或加法看作一步运算,那么这种方法要作O(n2)步运算才能求出乘积XY。下面我们用分治法来设计一个更有效的大整数乘积算法。 图6-3 大整数X和Y的分段 我们将n位的二进制整数X和Y各分为2段,每段的长为n/2位(为简单起见,假设n 是2的幂),如图6-3所示。 由此,X=A2n/2+B ,Y=C2n/2+D。这样,X和Y的乘积为: XY=(A2n/2+B)(C2n/2+D)=AC2n+(AD+CB)2n/2+BD (1) 如果按式(1)计算XY,则我们必须进行4次n/2位整数的乘法(AC,AD,BC和BD), 以及3次不超过n位的整数加法(分别对应于式(1)中的加号),此外还要做2次移位(分别对应于式(1)中乘2n和乘2n/2)。所有这些加法和移位共用O(n)步运算。设T(n)是2个n位整数相乘所需的运算总数,则由式(1),我们有:

(2) 由此可得T(n)=O(n2)。因此,用(1)式来计算X和Y的乘积并不比小学生的方法更有效。要想改进算法的计算复杂性,必须减少乘法次数。为此我们把XY写成另一种形式: XY=AC2n+[(A-B)(D-C)+AC+BD]2n/2+BD (3) 虽然,式(3)看起来比式(1)复杂些,但它仅需做3次n/2位整数的乘法(AC,BD和 (A-B)(D-C)),6次加、减法和2次移位。由此可得: (4) 用解递归方程的套用公式法马上可得其解为T(n)=O(n log3)=O(n1.59)。利用式(3),并考虑到X和Y的符号对结果的影响,我们给出大整数相乘的完整算法MULT如下: function MULT(X,Y,n); {X和Y为2个小于2n的整数,返回结果为X和Y的乘积XY} begin S:=SIGN(X)*SIGN(Y); {S为X和Y的符号乘积} X:=ABS(X); Y:=ABS(Y); {X和Y分别取绝对值} if n=1 then if (X=1)and(Y=1) then return(S) else return(0) else begin A:=X的左边n/2位; B:=X的右边n/2位; C:=Y的左边n/2位; D:=Y的右边n/2位; ml:=MULT(A,C,n/2); m2:=MULT(A-B,D-C,n/2); m3:=MULT(B,D,n/2); S:=S*(m1*2n+(m1+m2+m3)*2n/2+m3); return(S); end; end; 上述二进制大整数乘法同样可应用于十进制大整数的乘法以提高乘法的效率减少乘法次数。下面的例子演示了算法的计算过程。 设X=314l,Y=5327,用上述算法计算XY的计算过程可列表如下,其中带'号的数值是在计算完成AC,BD,和(A-B)(D-C)之后才填入的。

矩阵相乘的快速算法

矩阵相乘的快速算法 算法介绍 矩阵相乘在进行3D变换的时候是经常用到的。在应用中常用矩阵相乘的定义算法对其进行计算。这个算法用到了大量的循环和相乘运算,这使得算法效率不高。而矩阵相乘的计算效率很大程度上的影响了整个程序的运行速度,所以对矩阵相乘算法进行一些改进是必要的。 这里要介绍的矩阵算法称为斯特拉森方法,它是由v.斯特拉森在1969年提出的一个方法。 我们先讨论二阶矩阵的计算方法。 对于二阶矩阵 a11 a12 b11 b12 A = a21 a22 B = b21 b22 先计算下面7个量(1) x1 = (a11 + a22) * (b11 + b22); x2 = (a21 + a22) * b11; x3 = a11 * (b12 - b22); x4 = a22 * (b21 - b11); x5 = (a11 + a12) * b22; x6 = (a21 - a11) * (b11 + b12); x7 = (a12 - a22) * (b21 + b22); 再设C = AB。根据矩阵相乘的规则,C的各元素为(2) c11 = a11 * b11 + a12 * b21 c12 = a11 * b12 + a12 * b22 c21 = a21 * b11 + a22 * b21 c22 = a21 * b12 + a22 * b22 比较(1)(2),C的各元素可以表示为(3) c11 = x1 + x4 - x5 + x7 c12 = x3 + x5 c21 = x2 + x4 c22 = x1 + x3 - x2 + x6 根据以上的方法,我们就可以计算4阶矩阵了,先将4阶矩阵A和B划分成四块2阶矩阵,分别利用公式计算它们的乘积,再使用(1)(3)来计算出最后结果。 ma11 ma12 mb11 mb12 A4 = ma21 ma22 B4 = mb21 mb22 其中 a11 a12 a13 a14 b11 b12 b13 b14 ma11 = a21 a22 ma12 = a23 a24 mb11 = b21 b22 mb12 = b23 b24 a31 a32 a33 a34 b31 b32 b33 b34 ma21 = a41 a42 ma22 = a43 a44 mb21 = b41 b42 mb22 = b43 b44 实现 // 计算2X2矩阵 void Multiply2X2(float& fOut_11, float& fOut_12, float& fOut_21, float& fOut_22, float f1_11, float f1_12, float f1_21, float f1_22, float f2_11, float f2_12, float f2_21, float f2_22) { const float x1((f1_11 + f1_22) * (f2_11 + f2_22)); const float x2((f1_21 + f1_22) * f2_11); const float x3(f1_11 * (f2_12 - f2_22)); const float x4(f1_22 * (f2_21 - f2_11)); const float x5((f1_11 + f1_12) * f2_22);

Strassen算法-介绍

Strassen算法 在了解Strassen算法之前,先来了解一下矩阵乘法: 矩阵乘法的c语言程序: #include"stdio.h" float main() { float a[100][100],b[100][100],c[100][100]; //定义三个数组分别储存三个矩阵A,B,C int m1,n1,m2,n2,i1,j1,i2,j2,i3,j3,i4,j4,k; float s[100][100]={0}; //初始化数组s printf("请输入矩阵A的行数m1和列数n1:"); scanf("%d%d",&m1,&n1); printf("请输入矩阵B的行数m2和列数n2:"); scanf("%d%d",&m2,&n2); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); //便于观看结果,将结果与输入分开 if(n1!=m2) printf("不可以相乘!!!\n\n"); if(m1>100||n1>100||m2>100||n2>100) printf("数目过多,溢出!!!\n\n"); else{ for(i2=1;i2<=m2;i2++) for(j2=1;j2<=n2;j2++) { printf("A[%d][%d]=",i2,j2); scanf("%f",&a[i2][j2]); } //输入矩阵A的元素 printf(">>>>>>>>>>>>>>>>>>>>>>\n"); for(i2=1;i2<=m2;i2++) { for(j2=1;j2<=n2;j2++) { printf("B[%d][%d]=",i2,j2); scanf("%f",&b[i2][j2]); } //输入矩阵B的元素 } } printf("矩阵A\n\n"); //打印矩阵A便于观看与检查 for(i3=1;i3<=m1;i3++) { for(j3=1;j3<=n1;j3++) {printf("%f\t",a[i3][j3]); if(j3==n1)printf("\n");} } printf(">>>>>>>>>>>>>>>>>>>>>>>>>\n\n矩阵B:"); //与矩阵B的打印隔开,便于观看for(i4=1;i4<=m2;i4++) { for(j4=1;j4<=n2;j4++) {printf("%f\t",b[i4][j4]); if(j4==n2)printf("\n"); }} printf(">>>>>>>>>>>>>>>>>>>>>>>>>\n\n矩阵C=A*B= \n"); for(i4=1;i4<=m1;i4++) { for(j4=1;j4<=n2;j4++) {for(k=1;k<=n1;k++) {s[i4][j4]=s[i4][j4]+a[i4][k]*b[k][j4]; }//定义矩阵的乘法,相乘时,有一个指标是一样的,都用k c[i4][j4]=s[i4][j4];} printf("矩阵C是:\n");

矩阵乘法综述

矩阵乘法综述 摘要:本文重点对不同矩阵乘法算法的所用时间进行了分析。在本论文中,对Karatsuba和Strassen发明的方法进行了分析和实现;对理论和实际时间进行了计算。之后对Karatsuba和Strassen算法进行了合并,并结合这两种算法设计了一种新算法,它可以被看作是一个降低时间复杂度的方法。 关键词:时间复杂度,分治法 1. 介绍 在各种数学方法和科学分支中,矩阵乘法均被广泛的应用。例如,在生成如光通过浮动的水的这类具有反射和失真效果的计算机图像中,矩阵的数学方法被广泛的应用。除此之外,光科学利用这一种数学方法来解释反射和折射。同样的,它也被用来计算电路的电气性能。在数学中,矩阵符号也已应用于图论,一个临近矩阵可以表示临域关系。概率论和数理统计领域同样可以利用矩阵来表示。例如,一个概率向量可以表示一个试验中不同结果的概率。除此之外,计算机利用随机矩阵来运行马尔可夫链,以实现包括赌博、天气预报或量子力学的建模预测。矩阵数学通过提供一个更紧凑的方式来处理组中的线性代数方程组的方式简化了线性代数。因此,矩阵乘法被大量的应用于软件的实际施行当中。然而,矩阵乘法的软件操作变得非常缓慢,成为整个系统运行的障碍。硬件乘法器可以被应用于高速逻辑模块,但是其具有昂贵且缺少延伸能力的缺点。在矩阵乘法中,时间是一个重要的指标。本文的主要关注点是提出了一种矩阵乘法算法可以在实际运行中减少矩阵乘法的数量。本论文致力于提出一种利用分治法来减小乘法运算数量的方法。 这篇文章以以下的方式进行组织。第二部分包含了在矩阵乘法部分之前工作

的总结。第三部分描述了不同矩阵乘法的算法。第四部分展示了不同的实验和他们为矩阵乘法做出的准备。第五部分分析了实验的结果。第六部分总结全文并提出展望。 2.前期工作 大量的研究者对于矩阵乘法的时间和内存损耗进行了大量的研究,为了得到快速切不合并的方形矩阵的算法,前人进行了以下的研究工作。 Lingas[1],研究在最多b项不为零的情况下计算AB的问题。如果在相应计算点中的每一项均为零,那么可以将这个矩阵视为平凡零矩阵。矩阵中相乘计算中的零可能来自于取消,所以它可以远大于b数目中的b非零项。Lingas证明了这种针对快速方形矩阵乘法的简化可以将时间复杂度缩减到O(n2b0.188)。对于b=n2时间复杂度可以达到O n2.276,此结果由Coppersmith和Winograd完成界定。Lingas观察到通过一种列-行的组合算法,时间复杂度可以达到O(n2+b n)。 对于输入为稀疏矩阵的算法,Yuster和Zwick得出了一种根据矩阵划分思想的快速算法。随后Amossen和pagh将这种算法延伸到了输出矩阵也为稀疏矩阵的计算中。 Iwen和Spencer提出了利用压缩感知,对于任何已知常数ε>0,计算AB的算法,其时间复杂度为O(n2+ε)。当AB每一行包含最多n0.29462个非零值时,为特殊情况。 Strassen利用分治的思想提出了一种算法,其计算速度高于标准的矩阵相乘算法。在实际的大矩阵运算中具有优势,但是对于极端情况下的超大矩阵情况其速度低于已知的最快算法。 3.不同种类的矩阵乘法算法

相关主题
相关文档
最新文档