方阵行列式并行化计算(OpenMP,MPI),并计算加速比
以下内容为本人并行计算课程的期末作业,有不足的地方,请多多指教!
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),并计算加速比的更多相关文章
- Oracle计算连续天数,计算连续时间,Oracle连续天数统计
Oracle计算连续天数,计算连续时间,Oracle连续天数统计 >>>>>>>>>>>>>>>>> ...
- CyclicBarrier开启多个线程进行计算,最后统计计算结果
有一个大小为50000的数组,要求开启5个线程分别计算10000个元素的和,然后累加得到总和 /** * 开启5个线程进行计算,最后所有的线程都计算完了再统计计算结果 */ public class ...
- Chapter Zero 0.1.4 计算机上常用的计算单位
0.1 计算机硬件 计算机上常用的计算单位 容量单位: 计算机对于数据的判断依据有没有通电来记录信息,对于每个记录而言, 他只认识0或1,而0/1这个二进制单位我们成为bit. 因为bit太小,所以存 ...
- 对端边缘云网络计算模式:透明计算、移动边缘计算、雾计算和Cloudlet
对端边缘云网络计算模式:透明计算.移动边缘计算.雾计算和Cloudlet 概要 将数据发送到云端进行分析是过去几十年的一个突出趋势,推动了云计算成为主流计算范式.然而,物联网时代设备数量和数据流量的急 ...
- 数据分析与科学计算可视化-----用于科学计算的numpy库与可视化工具matplotlib
一.numpy库与matplotlib库的基本介绍 1.安装 (1)通过pip安装: >> pip install matplotlib 安装完成 安装matplotlib的方式和nump ...
- vue计算属性(通过计算得来的属性)
1.computed:是一个计算属性,用来监听属性的变化 eg: <p>computed:{{count}}</p> computed:{ count(){ c ...
- 卷积、矩阵乘积、高斯模糊滤波(降噪)、空域计算(2D卷积计算)、频域计算(FFT)的理解
矩阵乘积:对应行列对应元素相乘的和组成新的矩阵 两个矩阵的乘法仅当第一个矩阵A的列数和另一个矩阵B的行数相等时才能定义.如A是m×n矩阵和B是n×p矩阵,它们的乘积C是一个m×p矩阵 并将此乘积记为: ...
- R语言计算相关矩阵然后将计算结果输出到CSV文件
R语言计算出一个N个属性的相关矩阵(),然后再将相关矩阵输出到CSV文件. 读入的数据文件格式如下图所示: R程序采用如下语句: data<-read.csv("I:\\SB\land ...
- 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 ...
随机推荐
- 单页应用seo收录神器 -- seo-mask
前言 看到标题的人肯定会问,seo-mask是什么,为什么可以解决单页应用seo无法被收录的难题呢? 简单来讲seo-mask做的就是为已经发布线上运营的的单页应用项目建立另一个简单的利于seo的镜像 ...
- 一个关于原生 js 开发一款插件的前端教程
教程链接: http://www.codeasily.net/course/plugin_course/ 写的不是很好,前面比较松后面比较急,请大家见谅,本人也没多少年前端经验,拿以前写过的教程网站, ...
- FromHBITMAP 这个函数会丢失透明信息。
在用 FromHBITMAP 你会发现出来的图是带有黑边的,这是因为这个函数有个 bug,解决的办法是用下列的函数进行转换,大体意思就是自己 memcpy 不要用 FromHBITMAP 函数. Bi ...
- 使用pycharm手动搭建python语言django开发环境(三) 使用django的apps应用 添加应用静态文件
1)在django 工程目录中使用cmd命令行 敲入"python manage.py startapp app名称(例子为blog)" 2)在django工程目录中应该生成了bl ...
- oracle数据库中VARCHAR2(50 CHAR) 和VARCHAR2(50) 有啥区别?
VARCHAR2(50 char)这种类型的字段最多放50个字符,不够50个用空格填充:而VARCHAR2(50)最大允许存放50个字符,但是不足50个也不用空格填充.varchar2是变长字符串,与 ...
- [浪风JQuery开发]jquery最有意思的IFrame类似应用--值得深入研究
前几天一时兴起答应朋友的需求--做一个外国的企业网站: 本想做就做呗,可没想我辛辛苦苦用浪风认真php平台开发后,对方来一句我服务器不能安装其他程序,请给我用frame框架开发. 浪风那是一个苦字难言 ...
- Eclipse 创建 Java 接口
打开新建 Java 接口向导 新建 Java 接口向导可以创建新的 Java 接口.打开向导的方式有: 点击 File 菜单并选择 New > Interface 在 Package Explo ...
- posix正则表达式说明
转载自:http://baiy.cn/utils/_regex_doc/index.htm 正则表达式说明 简介 大体来讲,正则表达式的文法分为3种标准:BRE.ERE 和 ARE.其中 BER 和 ...
- db2将原表列notnull属性修改为null属性的方法
今天把自己遇到的一个小问题跟大家分享一下如何修改db2数据库表中列的属性--将列的非空属性改为允许空的属性,修改数据表的某一列属性其实很简单但是里面有需要细节需要dba注意,毕竟数据的安全才是最重要的 ...
- Linq to SQL 语法查询(子查询 & in操作 & join )
var 子查询 = from c in ctx.Customers where (from o in ctx.Ord ...