矩阵相乘-并行算法

上传人:小*** 文档编号:192960581 上传时间:2023-03-07 格式:DOC 页数:25 大小:208.50KB
返回 下载 相关 举报
矩阵相乘-并行算法_第1页
第1页 / 共25页
矩阵相乘-并行算法_第2页
第2页 / 共25页
矩阵相乘-并行算法_第3页
第3页 / 共25页
点击查看更多>>
资源描述
并行处理技术课程设计分析报告课程设计题目矩阵相乘并行算法设计姓名廖杰学号M202372880专业计算机技术任课教师金海 石宣化所在学院计算机科学与技术学院报告提交日期2023-01-13一、实验目的1、学习使用集群;2、掌握并行处理或分布计算的编程方法;3、学会以并行处理的思想分析问题。二、实验要求1、自行生成矩阵作为算法的输入;2、使用并行处理技术编程,例如:MPI、OpenMP、MR;3、矩阵大小至少为1000*1000;4、加速比越大成绩越高。三、实验内容3.1、矩阵的划分:对于矩阵相乘的并行算法,可以有三种:对矩阵按行划分、按列划分和棋盘式分块划分。和按行或列划分相比,棋盘式划分可以开发出更高的并行度。对于一个nn的方阵,棋盘划分最多可以使用n2个处理器进行并行计算,但使用按行或列分解最多可以使用n个。对矩阵相乘采用棋盘式划分的算法通常称作Cannon算法。A)行列划分又叫带状划分(Striped Partitioning),就是将矩阵整行或者整列分成若干个组,每个组指派给一个处理器。下图所例为4个CPU,88矩阵的带状划分。在带状划分情况下,每个CPU将会均匀分配到2行(列)数据。88矩阵变成了一个14或41的分块矩阵,每个CPU所属的分块矩阵大小为82或28。B)棋盘划分就是将矩阵分成若干个子矩阵,每个子矩阵指派给一个处理器,此时任一处理器均不包含整行或者整列。下图所示即为4个处理器情况下88矩阵的棋盘划分,其中处理器阵列为22,每个处理器分配到的子矩阵大小为44。矩阵划分成棋盘状可以和处理器连成二维网孔相对应。对于一个nn维矩阵和pp的二维处理器阵列,每个处理器均匀分配有(n/p)(n/p)=n2/p2个元素。使用棋盘式划分的矩阵相乘算法一般有两种,Cannon算法和Summa算法。SUMMA算法能够计算m*l的A矩阵和l*n的B矩阵相乘(m、l、n可不相等),而cannon算法只能实现n*n的A矩阵和n*n的B矩阵相乘,具有很大的局限性。3.2、算法原理A) 行划分法假设是M*N,计算前,将矩阵N发送给所有从进程,然后将矩阵M分块,将M中数据按行分给各从进程,在从进程中计算M中部分行数据和N的乘积,最后将结果发送给主进程。这里为了方便,有多少进程,就将M分了多少块,除最后一块外的其他数据块大小都相等,最后一块是剩下的数据,大小大于等于其他数据块大小,因为矩阵行数不一定整除进程数。最后一块数据在主进程中计算,其他的在从进程中计算。定义两个矩阵M和N,N所有进程都需要,M可以只在主进程中定义。其他的变量视主进程和从进程需要按要求定义在合适的位置。代码参见附录部分。B) Cannon算法Cannon算法的基本思想可以如下表示:假设两个矩阵A和B相乘,把A和B矩阵划分成p个方块,进程的编号从到,并在最初把子矩阵和分配给。虽然第i行的每个进程需要全部的个子矩阵,但我们还是能调度第i行个进程的计算,使得每个进程在任何时刻都是用不同的。每完成一次矩阵乘法,这些块在各进程之间被轮流使用,似的每次轮流之后每个进程都可以得到新的。对列使用同样的调度,则在任何时刻,任何进程至多拥有每个矩阵的一个块,在所有进程中,改算法需要的总内存量为。下图为此算法中不同进程上子矩阵乘法的调度过程。假如矩阵C=A*B,则C的 的计算公式如下:进程P 存储分块矩阵这一部分。块矩阵乘法要计算所有匹配的和 ,然而只有在主对角线的才是匹配的。因此需要采用循环移动分块矩阵的方法来使每个进程 都有一对可以直接相乘的匹配的块,具体方法如下:(1)将排第i行的块循环左移i个位置,将第列 块循环上移j个位置;(2) 进程执行乘一加运算,然后将移动得到的 块循环左移1个位置,将移动得到的 块循环上移1个位置;(3)重复第2步(一1)次,每次移动后进程执行乘一加运算。经过以上操作后就可以得到矩阵C的解。代码请参见附录部分C) Summa算法SUMMA 算法首先将A , B 和C 划分为相同大小的矩阵,对应放在mesh_r mesh_c 的二维mesh 上。 但SUMMA 算法将矩阵乘法分解为一系列的秩nb 修正, 即各处理器中的A 和B 分别被分解为nb 大小的列块和行块进行相乘,前面所说的分块尺寸就是指nb 的大小。算法中, 广播实现为逻辑处理器行环或列环上的流水线传送, 达到了计算与通信的重叠. 具体描述如算法1所示。C= 0for i= 0 t o k-1 step nb docur col = ic/ ncur row = ir / mif my col = cur rol 向本行广播A 从i mod (k/c) 列开始的nb 列, 存于Aif my row = cur row 向本列广播B 从i mod (k/r) 行开始的nb 行, 存于B C= AB end forSUMMA算法的核心思想是:各处理器收集来自同一行处理器中A矩阵子块的所有列和同一列处理器中B矩阵子块的所有行,然后将行列相乘后累加,形成一个C矩阵的分块矩阵。最后由rank=0的处理器将其他处理器的数据收集起来,形成最终的矩阵C。 SUMMA算法相较于cannon算法的优势只要体现在SUMMA算法能够计算m*l的A矩阵和l*n的B矩阵相乘(m、l、n可不相等),而cannon算法只能实现n*n的A矩阵和n*n的B矩阵相乘,具有很大的局限性。代码参见附录部分。3.3、程序运行结果对比分析A) 统一的实验条件矩阵大小:1000*1000;矩阵数字范围:010;矩阵数字分布是否随机:是;分配的进程数:9;B) 实验进程数解释由于Cannon算法本身局限性,要使用Cannon算法,必须满足进程数为整数的平方,比如1、4、9、16等。在本次的实验环境之下,经过多次对比分析,发现对于分行还是分块算法,进程数安排在815可以得到最理想的运行速度:进程数目过小则每个进程单独运算的时间过多,进程数过大则选路时间(进程与进程之间的通信时间)过长。而对比要求每个算法的进程相同,故此处选择进程数目为9.C) 算法运行时间对比Cannon算法运行时间如下:分行法运行时间如下:串行算法运行时间如下:由于Summa算法与Cannon算法思路几乎相同,而且在算法预处理阶段要比Cannon算法更耗时,故没有做多余的实验。算法分行CANNON串行时间1.218810s0.76s10.420s显而易见,单纯的运用分行算法所花费的时间是最短的。D) 结果分析Cannon算法相对于简单的行划分并行处理算法,其优势仅仅在于并行度可以更高(可达到N*N个进程,N为矩阵宽),但在并行度相同的情况下,其多出的预处理过程、矩阵发送与结果回收机制会占用更多的时间。3.4、程序调优A) 行划分算法优化1. 循环优化在预估计矩阵大小为10的倍数的基础上,对每一个步长为1的循环做处理,改为步长为10的循环,将十次循环体全部压缩在一次循环中,从而大量减少了循环的判别时间,提升循环运算速度。例如在单个线程在计算部分结果时,采用的循环为:for(i=0;iline;i+)for(j=0;jwidth;j+)DATA temp=0;for(k=0;kwidth;k+=10)temp += bufferi*width+k*nj*width+k;temp += bufferi*width+k+1*nj*width+k+1;temp += bufferi*width+k+2*nj*width+k+2;temp += bufferi*width+k+3*nj*width+k+3;temp += bufferi*width+k+4*nj*width+k+4;temp += bufferi*width+k+5*nj*width+k+5;temp += bufferi*width+k+6*nj*width+k+6;temp += bufferi*width+k+7*nj*width+k+7;temp += bufferi*width+k+8*nj*width+k+8;temp += bufferi*width+k+9*nj*width+k+9;ansi*width+j = temp;在将循环次数压缩的同时,为了进一步减少循环的运算量,在每一个步长为10的循环之前做预处理,避免循环体中的重复运算。例如在主进程在接受其他进程时,将结果矩阵整合的过程:for(k=1;knumprocs;k+) MPI_Recv(ans,line*width,MPI_INT,k,2,MPI_COMM_WORLD,&status); for(i=0;iline;i+) count=i*k*width; /将i*k*width提前算好,减少了下一步循环的重复运算 count1=i*width; for(j=0;jwidth;j+=10)pcount+j = anscount1+j;pcount+j+1 = anscount1+j+1;pcount+j+2 = anscount1+j+2;pcount+j+3 = anscount1+j+3;pcount+j+4 = anscount1+j+4;pcount+j+5 = anscount1+j+5;pcount+j+6 = anscount1+j+6;pcount+j+7 = anscount1+j+7;pcount+j+8 = anscount1+j+8;pcount+j+9 = anscount1+j+9;2.节省空间在进行矩阵工作量划分并传送的时候,为每一个进程开辟仅仅是自己所需要大小的空间,例如在9进程的环境下,每个进程所需要接受的缓存空间为B矩阵大小以及大约1/9大小A矩阵。内存开辟:buffer = (DATA *)malloc(sizeof(DATA)*width*line);矩阵A分块传输:for(k=1;knumprocs;k+)for(i=k;iwidth;i+=numprocs)count=i/numprocs*width;count1=i*width;for(j=0;jwidth;j+=10)buffercount+j=mcount1+j;buffercount+j+1=mcount1+j+1;buffercount+j+2=mcount1+j+2;buffercount+j+3=mcount1+j+3;buffercount+j+4=mcount1+j+4;buffercount+j+5=mcount1+j+5;buffercount+j+6=mcount1+j+6;buffercount+j+7=mcount1+j+7;buffercount+j+8=mcount1+j+8;buffercount+j+9=mcount1+j+9;MPI_Send(buffer,line*width,MPI_INT,k,1,MPI_COMM_WORLD);同样的方式也运用在运行空间的开辟上。这样做不仅仅是内存空间的节约,同时也减少了进程之间的数据传输量,大大节省了进程之间的协作时间!B) 稀疏矩阵处理虽然程序并未对稀疏矩阵进行优化,但是还是试着对程序的输入数据模式进行更改,体验一下稀疏矩阵运算的速度提升有多快。void magten(DATA *a,int width)int i,j;srand(unsigned)time(NULL);for(i=0;iwidth;i+)for(j=0;jwidth;j+=10)ai*width+j = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+1 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+2 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+3 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+4 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+5 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+6 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+7 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+8 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+9 = (rand()%MUL)*(rand()%2)*(rand()%3);如上面所示,对于每一个生成的数据都再一次进行乘法运算,其中乘数是0的概率为2/3.运行结果如下:可以看出,稀疏矩阵的乘法由0.76s变为0.75s,仅仅是短暂的提升。提升计时显示的精度,可以看到,对于稀疏矩阵的处理要比普通矩阵快0.015s,提速约为2%3.5、算法最优速度对算法运用不同的进程数目运算进行了大量重复试验,最终得出在进程数大概为12的时候,本算法的运行速度最快。最终结果如下:发出工作量时间为0.138184s运算时间为 0.495569s接收答案时间为 0.025461s总运算时间0.659240s四、总结分析串行并行行划分串行运行时间0.659240s10.420s进程数目121加速比15.801效率15.80/12=1.3171从效率大于1上可以看出,本次课程设计做出的算法为超线性加速,这主要得益于对循环体的优化。附录Cannon算法#include #include mpi.h#include #include #include #include #define MUL 10MPI_Status status;double *A, *B, *C; /C=A*Bdouble *a,*b,*c; /各个进程的缓冲区int n; /矩阵的行列数int np; /每个进程控制的小矩阵的行列数int p,rank; /进程个个数、当前进程的编号,笛卡尔进程编号double *tempa, *tempb;void ProduceABC(); /在根处理器中生成矩阵AB,初始化矩阵Cvoid PrintABC();/输出结果void ScatterAB();/ 分发矩阵AB中的元素到各个进程中void MainProcess(); /cannon算法的主过程void collectC(); /收集结果矩阵Cvoid Mutiply(); /矩阵相乘void Printab();void Printc();int main(int argc, char *argv) int i;double starttime,endtime;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &p);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if(rank = 0)printf(please input the raw number:n= ); fflush(stdout);scanf(%d, &n);printf(n);MPI_Bcast(&n, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);/ n = atoi(argv1);np = n/(int)sqrt(p);a = (double*)malloc(np*np*sizeof(double);b = (double*)malloc(np*np*sizeof(double);c = (double*)malloc(np*np*sizeof(double);memset(c, 0, np*np*sizeof(double);tempa = (double*)malloc(np*np*sizeof(double);tempb = (double*)malloc(np*np*sizeof(double); if(rank = 0) /在根处理器中为矩阵ABC分配空间A = (double*)malloc(n*sizeof(double*);B = (double*)malloc(n*sizeof(double*);C = (double*)malloc(n*sizeof(double*);for(i = 0; i n; i+)Ai = (double*)malloc(n*sizeof(double);Bi = (double*)malloc(n*sizeof(double);Ci = (double*)malloc(n*sizeof(double);ProduceABC(); /在根处理器中随机生成矩阵AB,初始化矩阵CScatterAB();/ 分发矩阵AB中的元素到各个进程中 elseMPI_Recv(a, np*np, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD, &status);MPI_Recv(b, np*np, MPI_DOUBLE, 0, 2, MPI_COMM_WORLD, &status); starttime=MPI_Wtime(); /开始时间MainProcess(); /cannon算法的主过程if(rank = 0)collectC(); /收集结果矩阵CPrintABC(); /输出结果endtime=MPI_Wtime(); printf(time used: %lfn,endtime - starttime);for(i = 0; i n; i+)free(Ai);free(Bi);free(Ci);free(A);free(B);free(C);else MPI_Send(c, np*np, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);free(a);free(b);free(c);free(tempa);free(tempb);MPI_Finalize();return 0;void ProduceABC()/在根处理器中生成矩阵AB int i,j;srand(unsigned)time(NULL);for(i=0; in; i+)for(j=0; jn; j+)Aij=rand()%MUL;Bij=rand()%MUL;Cij=0.0;void PrintABC()/输出结果printf(A00=%fnB00=%fnC00=%fn,A00,B00,C00); void ScatterAB()/ 分发矩阵AB中的元素到各个进程中int imin,imax,jmin,jmax;int sp;int i,j,k,m;for(k=0; kp; k+)/*计算相应处理器所分得的矩阵块在总矩阵中的坐标范围*/sp = (int)sqrt(p);imin = (k / sp) * np;imax = imin + np - 1; jmin = (k % sp) * np;jmax = jmin + np -1;/*rank=0的处理器将A,B中的相应块拷至tempa,tempb,准备向其他处理器发送*/m = 0; for(i=imin; i=imax; i+)for(j=jmin; j=jmax; j+) tempam = Aij; tempbm = Bji; /矩阵B按列优先存储 m+;/*根处理器将自己对应的矩阵块从tempa,tempb拷至a,b*/if(k=0)memcpy(a, tempa, np*np*sizeof(double);memcpy(b, tempb, np*np*sizeof(double); else /*根处理器向其他处理器发送tempa,tempb中相关的矩阵块*/MPI_Send(tempa, np*np, MPI_DOUBLE, k, 1, MPI_COMM_WORLD);MPI_Send(tempb, np*np, MPI_DOUBLE, k, 2, MPI_COMM_WORLD);void MainProcess() /cannon算法的主过程MPI_Comm comm; /笛卡尔结构通讯器int crank;int dims2,periods2, coords2;int source, dest, up, down, right, left;int i;dims0 = dims1 = (int)sqrt(p);periods0 = periods1 = 1;MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 1, &comm);MPI_Comm_rank(comm, &crank);MPI_Cart_coords(comm, crank, 2, coords);MPI_Cart_shift(comm, 1, -1, &right, &left);MPI_Cart_shift(comm, 0, -1, &down, &up);MPI_Cart_shift(comm, 1, -coords0, &source, &dest);MPI_Sendrecv_replace(a, np*np, MPI_DOUBLE, dest, 1, source, 1, comm, &status);MPI_Cart_shift(comm, 0, -coords1, &source, &dest);MPI_Sendrecv_replace(b, np*np, MPI_DOUBLE, dest, 1, source, 1, comm, &status);Mutiply(); /矩阵相乘for(i = 1; i dims0; i+)MPI_Sendrecv_replace(a, np*np, MPI_DOUBLE, left, 1, right, 1, comm, &status);MPI_Sendrecv_replace(b, np*np, MPI_DOUBLE, up, 1, down, 1, comm, &status);Mutiply(); /矩阵相乘MPI_Comm_free(&comm);void collectC() /收集结果矩阵Cint i,j,k,s,m;int imin,imax,jmin,jmax;int sp= (int)sqrt(p);/* 根处理器中的c赋给总矩阵C */for (i=0;inp;i+)for(j=0;jnp;j+)Cij=ci*np+j;for (k=1;kp;k+)/*根处理器从其他处理器接收相应的分块c*/MPI_Recv(c, np*np, MPI_DOUBLE, k, 1, MPI_COMM_WORLD, &status);/printf(rank = %dn, k);Printc();imin = (k / sp) * np;imax = imin + np - 1; jmin = (k % sp) * np;jmax = jmin + np -1;/*将接收到的c拷至C中的相应位置,从而构造出C*/for(i=imin,m=0; i=imax; i+,m+)for(j=jmin,s=0; j=jmax; j+,s+)Cij=cm*np+s; void Mutiply() /矩阵相乘int i,j,k;for(i=0; inp; i+) for(j=0; jnp; j+)for(k=0; knp; k+)ci*np+j += ai*np+k*bj*np+k; /b按列优先来搞优化后的行划分算法(带稀疏)#include mpi.h#include #include #include #define DATA int#define MUL 3void magten(DATA *a,int width)int i,j;srand(unsigned)time(NULL);for(i=0;iwidth;i+)for(j=0;jwidth;j+=10)ai*width+j = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+1 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+2 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+3 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+4 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+5 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+6 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+7 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+8 = (rand()%MUL)*(rand()%2)*(rand()%3);ai*width+j+9 = (rand()%MUL)*(rand()%2)*(rand()%3);void matrix_c(DATA *a,int width)int i,j;DATA temp;for(i=0;iwidth;i+)for(j=i;jwidth;j+)temp = ai*width+j;ai*width+j = aj*width+i;aj*width+i = temp;void print_matrix(DATA *a,int width)int i,j;for(i=0;iwidth;i+)for(j=0;jwidth;j+)printf(%d ,ai*width+j);printf(n);int main(int argc,char *argv)DATA *m,*n,*p,*buffer,*ans;int width = 1000;int count,count1;int myid,numprocs;MPI_Status status;int i,j,k;MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&myid);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);int line = width/numprocs;if(myid = 0)m = (DATA *)malloc(sizeof(DATA)*width*width);n = (DATA *)malloc(sizeof(DATA)*width*width);p = (DATA *)malloc(sizeof(DATA)*width*width);buffer = (DATA *)malloc(sizeof(DATA)*width*line);ans = (DATA *)malloc(sizeof(DATA)*width*line);magten(m,width);magten(n,width);matrix_c(n,width);doubleclockstart = MPI_Wtime();for(i=1;inumprocs;i+)MPI_Send(n,width*width,MPI_INT,i,0,MPI_COMM_WORLD);for(k=1;knumprocs;k+)for(i=k;iwidth;i+=numprocs)count=i/numprocs*width;count1=i*width;for(j=0;jwidth;j+=10)buffercount+j=mcount1+j;buffercount+j+1=mcount1+j+1;buffercount+j+2=mcount1+j+2;buffercount+j+3=mcount1+j+3;buffercount+j+4=mcount1+j+4;buffercount+j+5=mcount1+j+5;buffercount+j+6=mcount1+j+6;buffercount+j+7=mcount1+j+7;buffercount+j+8=mcount1+j+8;buffercount+j+9=mcount1+j+9;MPI_Send(buffer,line*width,MPI_INT,k,1,MPI_COMM_WORLD);double time1 = MPI_Wtime();printf(send B and Ai time:%.6fn,(time1-clockstart); for(i=0;iwidth;i+=numprocs) for(j=0;jwidth;j+) DATA temp = 0; for(k=0;kwidth;k+=10) temp+=mi*width+k*nj*width+k;temp+=mi*width+k+1*nj*width+k+1;temp+=mi*width+k+2*nj*width+k+2;temp+=mi*width+k+3*nj*width+k+3;temp+=mi*width+k+4*nj*width+k+4;temp+=mi*width+k+5*nj*width+k+5;temp+=mi*width+k+6*nj*width+k+6;temp+=mi*width+k+7*nj*width+k+7;temp+=mi*width+k+8*nj*width+k+8;temp+=mi*width+k+9*nj*width+k+9; pi*width+j = temp; double time2 = MPI_Wtime();printf(compute the last Ai time:%.6fn,(time2-time1); for(k=1;knumprocs;k+) MPI_Recv(ans,line*width,MPI_INT,k,2,MPI_COMM_WORLD,&status); for(i=0;iline;i+) count=i*k*width; count1=i*width; for(j=0;jwidth;j+=10)pcount+j = anscount1+j;pcount+j+1 = anscount1+j+1;pcount+j+2 = anscount1+j+2;pcount+j+3 = anscount1+j+3;pcount+j+4 = anscount1+j+4;pcount+j+5 = anscount1+j+5;pcount+j+6 = anscount1+j+6;pcount+j+7 = anscount1+j+7;pcount+j+8 = anscount1+j+8;pcount+j+9 = anscount1+j+9;double time3 = MPI_Wtime();printf(receive the results from slave time :%.6fn,(time3-time2);double clockend = MPI_Wtime();/print_matrix(p,width);free(m);free(n);free(p);free(ans);free(buffer);printf(myid:%d time:%.6fsecsn,myid,(clockend-clockstart);elsen = (DATA *)malloc(sizeof(DATA)*width*width);ans = (DATA *)malloc(sizeof(DATA)*width*line);buffer = (DATA *)malloc(sizeof(DATA)*width*line);MPI_Recv(n,width*width,MPI_INT,0,0,MPI_COMM_WORLD,&status);MPI_Recv(buffer,width*line,MPI_INT,0,1,MPI_COMM_WORLD,&status);for(i=0;iline;i+)for(j=0;jwidth;j+)DATA temp=0;for(k=0;kwidth;k+=10)temp += bufferi*width+k*nj*width+k;temp += bufferi*width+k+1*nj*width+k+1;temp += bufferi*width+k+2*nj*width+k+2;temp += bufferi*width+k+3*nj*width+k+3;temp += bufferi*width+k+4*nj*width+k+4;temp += bufferi*width+k+5*nj*width+k+5;temp += bufferi*width+k+6*nj*width+k+6;temp += bufferi*width+k+7*nj*width+k+7;temp += bufferi*width+k+8*nj*width+k+8;temp += bufferi*width+k+9*nj*width+k+9;ansi*width+j = temp;MPI_Send(ans,width*line,MPI_INT,0,2,MPI_COMM_WORLD);/free(n);/free(ans);/free(buffer);MPI_Finalize();return0;串行算法#include #include #include #include #define DATA int#define MUL 10void magten(DATA *a,int width)int i,j;srand(unsigned)time(NULL);for(i=0;iwidth;i+)for(j=0;jwidth;j+=10)ai*width+j = rand()%MUL;ai*width+j+1 = rand()%MUL;ai*width+j+2 = rand()%MUL;ai*width+j+3 = rand()%MUL;ai*width+j+4 = rand()%MUL;ai*width+j+5 = rand()%MUL;ai*width+j+6 = rand()%MUL;ai*width+j+7 = rand()%MUL;ai*width+j+8 = rand()%MUL;ai*width+j+9 = rand()%MUL;void matrix_c(DATA *a,int width)int i,j;DATA temp;for(i=0;iwidth;i+)for(j=i;jwidth;j+)temp = ai*width+j;ai*width+j = aj*width+i;aj*width+i = temp; int main(int argc, char const *argv)DATA *A,*B,*C;/* code */int n;time_t starttime;struct tm *curTime;time_t endTime; int i,j,k;clock_t t1,t2;double tt;printf(please input the number of the raws&cols nn=);fflush(stdout);scanf(%d,&n);printf(okn); A=(DATA *)malloc(sizeof(DATA)*n*n); B=(DATA *)malloc(sizeof(DATA)*n*n); C=(DATA *)malloc(sizeof(DATA)*n*n);magten(A,n);magten(B,n);matrix_c(B,n);time(&starttime);curTime=localtime(&starttime);t1=clock();printf(Now the serial computing begins! %s n,asctime(curTime);for (i = 0; i n; +i)for (j = 0; j n; +j)Ci*n+j=0;for (k = 0; k tm_hour,curTime-tm_min,curTime-tm_sec);tt=(double)(t2-t1)/CLOCKS_PER_SEC); printf(serial computing lasts:%.6lf secondsn,tt); free(A); free(B); free(C); free(curTime); getchar();getchar();return 0;
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸设计 > 毕设全套


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!