以下内容为本人并行计算课程的期末作业,有不足的地方,请多多指教!

1 实验目的

本实验的目的主要有以下三点:

1、 实现方阵行列式的计算。

2、 实现方阵行列式的并行计算,分别基于 OpenMP和 MPI。

3、 比较以上三种算法的运行时间,计算加速比。

2 实验设计

2.1 生成方阵

为方便,本实验的方阵不采取手动输入的方式,而是使用随机数来生成矩阵元素。

我定义了一个全局方阵变量——int p[100][100]。在创建方阵时,方阵的阶数N(N<100)由外部输入。然后用两层“for循环”来给方阵 p左上角 N×N个位置赋值。具体实现如下:

/*
* 定义矩阵阶数N
*/ int N; /*
* 定义一个全局矩阵
*/ int p[100][100]; /*
* 用随机数生成矩阵
*/ void create(){
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++) {
int a=rand()%15;//产生随机数,并赋给数组
p[i][j]=a;
}
}
}

2.2 打印矩阵

将生成的矩阵输出,以便验算其计算行列式的正确性。具体实现如下:

/*
* 输出矩阵
*/ void print()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ",p[i][j]);
printf("\n");
}
}

2.3 计算矩阵行列式

计算矩阵行列式的方法有很多,本实验选择的方法是:行列式按行展开法。行列式等于它任一行的各元素与其对应的代数余子式乘积之和。代数余子式:A(ij)=(-1)^(i+j)M(ij).  (ij)为下标。某个元素的余子式等于原行列式划去该元素所在的行和列。本实验采取按第一行展开的方法。即:将高阶的行列式按第一行展开,一直重复展开行为,直到阶数为 1。上述过程可用递归完成。

2.3.1 递归实现代码

根据上面的理论,我们容易得出如下的实现方法:

/*
* 计算行列式的函数
*/ long long mydet(int p [100][100],int n){
if(n==1) //n=1返回矩阵的唯一数,停止递归
return p[0][0];
else{
long long sum=0;
for(int i=0;i<n;i++)
{
int pp[100][100];//用于存放少一维的矩阵,为方便直接定义为100×100.
for(int j=1,j1=0;j<n;j++)//去掉第一行
{
for(int k=0,k1=0;k<n;k++)
{
if(k==i)
;//去掉对应的列
else
{ pp[j1][k1]=p[j][k];//pp为余子式
k1++;
}
}
j1++;
}
if(i%2)
sum+=(-1)*p[0][i]*mydet(pp,n-1);
else
sum+=p[0][i]*mydet(pp,n-1);
}
return sum;
}
}

2.4  实现串行\OpenMP\MPI计算

我这里的并行主要是放在第一次的按行展开那,具体实现看代码吧。

2.4.1  串行代码

/*************************************************************************
> File Name: matrix_det.c
> Author: surecheun
> Mail: surecheun@163.com
> Created Time: 2017年12月06日 星期三 17时28分00秒
************************************************************************/
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<time.h>
/*
* 定义矩阵阶数N
*/ int N; /*
* 定义一个全局矩阵
*/ int p[100][100]; /*
* 用随机数生成矩阵
*/ void create(){
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++) {
int a=rand()%15;//产生随机数,并赋给数组
p[i][j]=a;
}
}
} /*
* 输出矩阵
*/ void print()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ",p[i][j]);
printf("\n");
}
} /*
* 计算行列式的函数
*/ long long mydet(int p [100][100],int n){
if(n==1) //n=1返回矩阵的唯一数,停止递归
return p[0][0];
else{
long long sum=0;
for(int i=0;i<n;i++)
{
int pp[100][100];//用于存放少一维的矩阵,为方便直接定义为100×100.
for(int j=1,j1=0;j<n;j++)//去掉第一行
{
for(int k=0,k1=0;k<n;k++)
{
if(k==i)
;//去掉对应的列
else
{ pp[j1][k1]=p[j][k];//pp为余子式
k1++;
}
}
j1++;
}
if(i%2)
sum+=(-1)*p[0][i]*mydet(pp,n-1);
else
sum+=p[0][i]*mydet(pp,n-1);
}
return sum;
}
} int main(){
printf("N= ");
scanf("%d",&N);
while(N){ //如果输入N就可以继续算下去,这个设计主要为了方便获取时间数据来计算平均用时
create();
print();
clock_t start_t=clock(); //开始计时
printf("the sum of 串行 is %lld .\n",mydet(p,N));
clock_t end_t=clock(); //结束计时
double runing_t =(double)(end_t-start_t)/CLOCKS_PER_SEC;
printf("the runing time of 串行 is %f s.",runing_t); //输出时间
printf("\n");
printf("N= ");
scanf("%d",&N);
} return 0;
}

2.4.2 OpenMP代码

/*************************************************************************
> File Name: matrix_det_omp.c
> Author: surecheun
> Mail: surecheun@163.com
> Created Time: 2017年12月07日 星期四 17时23分51秒
************************************************************************/ #include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<time.h>
#include<omp.h> /*
* 定义线程数
*/
#define n_threads 2 /*
*定义矩阵的阶数为全局变量
*/ int N; /*
* 定义一个全局矩阵
*/ int p[100][100]; /*
* 用随机数生成矩阵
*/ void create(){
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++) {
int a=rand()%15;//产生随机数,并赋给数组
p[i][j]=a;
}
}
} /*
* 输出矩阵
*/ void print()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ",p[i][j]);
printf("\n");
}
} /*
* 计算行列式的函数
*/ long long mydet(int p [100][100],int n){
if(n==1) //n=1返回矩阵的唯一数,停止递归
return p[0][0];
else{
long long sum=0;
for(int i=0;i<n;i++)
{
int pp[100][100];
for(int j=1,j1=0;j<n;j++)//去掉第一行
{
for(int k=0,k1=0;k<n;k++)
{
if(k==i)//去掉和改数相同的列
;
else
{ pp[j1][k1]=p[j][k]; //pp为代数余子式
k1++;
}
}
j1++;
}
if(i%2)
sum+=(-1)*p[0][i]*mydet(pp,n-1);
else
sum+=p[0][i]*mydet(pp,n-1);
}
return sum;
}
} int main(){
printf("N= ");
scanf("%d",&N);
while(N){ //如果输入的N>0,则继续计算
create(); //创建矩阵
print(); //打印创建的矩阵
double start1,finish1;
start1=omp_get_wtime(); //开始计算时间
long long sum=0;
omp_set_num_threads(n_threads);//设置线程数
#pragma omp parallel for reduction(+:sum)//并行化
for(int i=0;i<N;i++)
{
int pp[100][100];
for(int j=1,j1=0;j<N;j++)//去掉第一行
{
for(int k=0,k1=0;k<N;k++)
{
if(k==i)//去掉和i相同的列
;
else
{ pp[j1][k1]=p[j][k]; //pp为余子式
k1++;
}
}
j1++;
}
if(i%2)
sum+=(-1)*p[0][i]*mydet(pp,N-1);
else
sum+=p[0][i]*mydet(pp,N-1);
}
printf("the sum of omp is %lld .\n",sum);//输出结果
finish1=omp_get_wtime(); //结束计算时间
double runing_t =finish1-start1;
printf("the runing time of opm is %f s.",runing_t);//输出时间
printf("\n");
printf("N= ");
scanf("%d",&N);
}
return 0;
}

2.4.3 MPI实现代码

/*************************************************************************
> File Name: matrix_det_mpi.c
> Author: surecheun
> Mail: surecheun@163.com
> Created Time: 2017年12月07日 星期四 16时24分03秒
************************************************************************/ #include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<mpi.h> /*
*定义矩阵的阶数为全局变量
*/ int N; /*
* 定义一个全局矩阵
*/ int p[100][100]; /*
* 用随机数生成矩阵
*/ void create(){
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++) {
int a=rand()%15;//产生随机数,并赋给数组
p[i][j]=a;
}
}
} /*
* 输出矩阵
*/ void print()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ",p[i][j]);
printf("\n");
}
} /*
* 计算行列式的函数
*/ long long mydet(int p [100][100],int n){
if(n==1) //n=1返回矩阵的唯一数,停止递归
return p[0][0];
else{
long long sum=0;
for(int i=0;i<n;i++)
{
int pp[100][100];
for(int j=1,j1=0;j<n;j++)//去掉第一行
{
for(int k=0,k1=0;k<n;k++)
{
if(k==i)
;
else
{ pp[j1][k1]=p[j][k];
k1++;
}
}
j1++;
}
if(i%2)
sum+=(-1)*p[0][i]*mydet(pp,n-1);
else
sum+=p[0][i]*mydet(pp,n-1);
}
return sum;
}
} int main(int argc,char *argv[]){
scanf("%d",&N);
int num_procs,my_rank;
double start = 0.0, stop = 0.0; //记录时间的变量
long long per_procs = 0.0; //记录每个进程算的和
long long result = 0.0; //矩阵行列式结果
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if (my_rank == 0)
{//0号线程创建矩阵
create();
print(); //打印创建的矩阵
}
start = MPI_Wtime(); //开始计算时间 MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); //将矩阵大小广播给所有进程
for (int i = 0; i <N; i++)
{
MPI_Bcast(p[i],N, MPI_INT, 0, MPI_COMM_WORLD);
} //将矩阵广播给所有进程 for (int i = my_rank; i <N; i += num_procs){ //每个线程处理不同的行和列
long long sum_i=0;
int pp[100][100];
for(int j=1,j1=0;j<N;j++)//去掉第一行
{
for(int k=0,k1=0;k<N;k++)
{
if(k==i)
;
else
{
pp[j1][k1]=p[j][k];
k1++;
}
}
j1++;
}
if(i%2)
sum_i=(-1)*p[0][i]*mydet(pp,N-1);
else
sum_i=p[0][i]*mydet(pp,N-1);
per_procs += sum_i; //记录每个进程的和
}
MPI_Reduce(&per_procs, &result, 1, MPI_LONG_LONG_INT, MPI_SUM, 0, MPI_COMM_WORLD);//在0号进程求总和
if (my_rank == 0){
printf("the sum of mpi is %lld .\n",result) ;
stop = MPI_Wtime(); //结束计算时间
printf("the time of mpi is %f s\n", stop - start);
fflush(stdout);
}
MPI_Finalize();
return 0;
}

4 实验结果

4.1 正确性

4.1.1串行

结果分析,以 n=4为例,输出的矩阵为:

13

1

12

10

8

10

1

12

9

1

2

7

5

4

8

1

输出结果为:3875

和matlab计算结果一致!

4.1.2 OpenMP

结果分析,以 n=4为例,输出的矩阵为:

5

0

8

1

1

5

11

3

2

5

1

1

0

0

14

12

输出结果为:-2710

和matlab计算结果一致!

4.1.3 MPI

结果分析,以n=4为例,输出矩阵为:

9

1

2

7

5

4

8

1

0

6

7

1

11

8

12

9

输出结果为:-202

和matlab计算结果一致!

4.2 加速比

通过多次求平均,得到三种计算实现方法的计算时间(保留 3 位有效数字)如下:

N(阶数)

串行

OpenMP

MPI

9

0.0239s

0.0117s

0.0117s

10

0.195s

0.105s

0.100s

柱状图如下:

方阵行列式并行化计算(OpenMP,MPI),并计算加速比的更多相关文章

  1. Oracle计算连续天数,计算连续时间,Oracle连续天数统计

    Oracle计算连续天数,计算连续时间,Oracle连续天数统计 >>>>>>>>>>>>>>>>> ...

  2. CyclicBarrier开启多个线程进行计算,最后统计计算结果

    有一个大小为50000的数组,要求开启5个线程分别计算10000个元素的和,然后累加得到总和 /** * 开启5个线程进行计算,最后所有的线程都计算完了再统计计算结果 */ public class ...

  3. Chapter Zero 0.1.4 计算机上常用的计算单位

    0.1 计算机硬件 计算机上常用的计算单位 容量单位: 计算机对于数据的判断依据有没有通电来记录信息,对于每个记录而言, 他只认识0或1,而0/1这个二进制单位我们成为bit. 因为bit太小,所以存 ...

  4. 对端边缘云网络计算模式:透明计算、移动边缘计算、雾计算和Cloudlet

    对端边缘云网络计算模式:透明计算.移动边缘计算.雾计算和Cloudlet 概要 将数据发送到云端进行分析是过去几十年的一个突出趋势,推动了云计算成为主流计算范式.然而,物联网时代设备数量和数据流量的急 ...

  5. 数据分析与科学计算可视化-----用于科学计算的numpy库与可视化工具matplotlib

    一.numpy库与matplotlib库的基本介绍 1.安装 (1)通过pip安装: >> pip install matplotlib 安装完成 安装matplotlib的方式和nump ...

  6. vue计算属性(通过计算得来的属性)

    1.computed:是一个计算属性,用来监听属性的变化 eg: <p>computed:{{count}}</p> computed:{     count(){     c ...

  7. 卷积、矩阵乘积、高斯模糊滤波(降噪)、空域计算(2D卷积计算)、频域计算(FFT)的理解

    矩阵乘积:对应行列对应元素相乘的和组成新的矩阵 两个矩阵的乘法仅当第一个矩阵A的列数和另一个矩阵B的行数相等时才能定义.如A是m×n矩阵和B是n×p矩阵,它们的乘积C是一个m×p矩阵 并将此乘积记为: ...

  8. R语言计算相关矩阵然后将计算结果输出到CSV文件

    R语言计算出一个N个属性的相关矩阵(),然后再将相关矩阵输出到CSV文件. 读入的数据文件格式如下图所示: R程序采用如下语句: data<-read.csv("I:\\SB\land ...

  9. poj 1265 Area【计算几何:叉积计算多边形面积+pick定理计算多边形内点数+计算多边形边上点数】

    题目:http://poj.org/problem?id=1265 Sample Input 2 4 1 0 0 1 -1 0 0 -1 7 5 0 1 3 -2 2 -1 0 0 -3 -3 1 0 ...

随机推荐

  1. android studio- Gradle "xxx" project refresh failed

    Android Studio每次更新版本都会更新Gradle这个插件,但由于长城的问题每次更新都是失败,又是停止在Refreshing Gradle Project ,有时新建项目的时候报 Gradl ...

  2. spark-streaming的checkpoint机制源码分析

    转发请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/7994357.html spark-streaming定时对 DStreamGraph 和 JobS ...

  3. python学习之lambda()

    中学时期,数学老师不时在口中说着:“拉姆达!λ...”.这里的“拉姆达”表示第十一个希腊字母. 而在python中,lambda表示匿名函数. 先来看看匿名函数 >>> f = la ...

  4. Shallow Heap & Retained Heap

    所有包含Heap Profling功能的工具(MAT, Yourkit, JProfiler, TPTP等)都会使用到两个名词,一个是Shallow Size,另一个是 Retained Size. ...

  5. Spring Hello World 实例

    Hello World 实例 让我们使用 Spring 框架开始实际的编程.在你开始使用 Spring 框架编写第一个例子之前,你必须确保已经正确地设置了 Spring 环境,正如在 Spring—— ...

  6. python 面试题 string int

    str1 = 'hello' str2 = str1 str3 = str1 str4 = str1 str1 = '' int1 = 1 int2 = int1 int3 = int1 int4 = ...

  7. ZJU 17th 校赛

    第一次参加校赛,和小伙伴们拿了7个气球,还是挺开心的.  简单记个流水账吧. A:判断出INF的情况后 暴力模拟即可. INF的情况有x=1 || y=1 || (x==2 && y= ...

  8. 在Ubuntu中搭建***服务

    1) install shadowsocks$ sudo apt-get install python-pip $ sudo pip install shadowsocks 2) write /etc ...

  9. python3----字符串中的字符倒转

    方法一,使用[::-1]: s = 'python' print(s[::-1]) 方法二,使用reverse()方法: n = list(s) n.reverse() print(''.join(n ...

  10. MySQL左连接查询

    1.语法: select 字段列表 from table1 别名1 left join table2 别名2 on 连接条件 [where 子句]