문제1
Simpson 적분공식을 활용한 1차원 정적분 프로그램을 고려한다. 주어진 시작 프로그램(C 또는 FORTRAN)을 병렬화(MPI/OpenMP)시켜서 주어진 시스템에서 적분값과 총 함수 호출 횟수를 출력하시오. 또한, 최대 병렬 효율 성능을 구하시오. 여기서 사용된 Simpson 정적분 공식은 구간 [a,b]에 대한 정적분을 의미하고, n+1개의 함수값을 호출하게 되어 있다. 여기서 n은 짝수 이다. 실제 정적분값은 다음의 수식으로 근사된다. (h/3)[f(x0)+4f(x1)+2f(x2)+....+4f(xn-1)+f(xn)]. 여기서, h=(b-a)/n 이며, xi=a+ih이고, f(x)=4/(1+x2)이다. 주의할 점은 함수 호출을 n+1번만 수행한다.
Simpson 적분공식은 검색해보면 이와 같다. 다시말해, x0와 xn을 제외한 부분을 1차 FDM으로 계산하면 된다.
sequential.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<sys/time.h>
int ncall;
typedef enum { FALSE=0, TRUE=1} boolean;
float gettime();
double func(double x){
ncall ++;
return 4.L/(x*x+1.L);
}
double simpson0(double (*func1)(double),int n,double aa,double bb){
double h,xx,rslt;
boolean lodd;
int j;
if((n%2) !=0){
fprintf(stderr,"input error, n must be even number %d\n",n);
exit(9);
}
rslt = 0.L;
h = (bb-aa)/(double)n;
rslt = (func1(aa) + func1(bb));
for(lodd = TRUE,j = 1; j<n;j++){
xx = aa + h * (double)j;
if(lodd) {
rslt += 4.L*func1(xx);
}
else {
rslt += 2.L*func1(xx);
}
lodd = ((lodd)? (FALSE):(TRUE));
}
rslt = rslt*h/3.L;
return rslt;
}
int main(int argc, char **argv){
double rslt,aa,bb;
int n;
double time_start,time_end;
time_start = gettime();
n = 2000000000;
aa = 0.L;
bb = 1.L;
ncall = 0;
rslt = simpson0(func,n,aa,bb);
time_end = gettime();
printf("%d %18.16g n, rslt,%d\n",n,rslt,ncall);
printf("Wallclock time %g\n",time_end-time_start);
return 0;
}
struct timeval tv;
float gettime()
{
static int startflag=1;
static double tsecs0, tsecs1;
if( startflag ) {
(void ) gettimeofday(&tv,0);
tsecs0 = tv.tv_sec + tv.tv_usec*1.0e-6;
startflag = 0;
}
(void) gettimeofday(&tv,0);
tsecs1 = tv.tv_sec + tv.tv_usec*1.0e-6;
return ((float) (tsecs1-tsecs0));
}
answer.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>
#define min(a,b) ((a)<(b)?(a):(b))
int ncall;
double simpson2(double (*func1)(double),int , double , double , int , int );
double func(double x){
ncall ++;
return 4.L/(x*x+1.L);
}
int main(int argc, char **argv){
double rslt,aa,bb,rslt0;
int n,ncall0;
int ierr, kount, iroot;
int myid,nproc;
double time1,time2,time_start, time_end;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Comm_size(MPI_COMM_WORLD,&nproc);
if(myid ==0 && nproc > 1) printf("%d processes are alive\n",nproc);
if(myid ==0 && nproc == 1) printf("%d processes is alive\n",nproc);
time_start = MPI_Wtime();
n=20;
n =6;
n = 200000;
n = 2000000000;
aa = 0.L;
bb = 1.L;
ncall = 0;
ncall = 0;
rslt = simpson2(func,n,aa,bb,myid,nproc);
iroot = 0; kount = 1;
MPI_Reduce(&rslt,&rslt0, kount, MPI_DOUBLE, MPI_SUM,iroot, MPI_COMM_WORLD);
if(myid==0) printf("%d %18.14g n, rslt0\n",n,rslt0);
iroot = 0; kount = 1;
MPI_Reduce(&ncall, &ncall0,kount,MPI_INT,MPI_SUM,iroot, MPI_COMM_WORLD);
if(myid==0) printf("%d ncall0\n",ncall0);
time_end = MPI_Wtime();
if(myid==0) {
double timer = time_end - time_start;
double timerm = timer/60.L;
double timerh = timer/3600.L;
double timerd = timer/3600.L/24.L;
printf("%14.5g s %14.5g m %14.5g h %14.5g d\n",timer, timerm,timerh,timerd);
}
MPI_Finalize();
return 0;
}
void equal_load(int n1, int n2, int nproc, int myid, int *istart, int *ifinish){
int iw1,iw2;
iw1 = (n2-n1+1)/nproc;
iw2 = (n2-n1+1)%nproc;
*istart = myid*iw1+n1+min(myid,iw2);
*ifinish= *istart +iw1 -1;
if(iw2>myid) *ifinish = *ifinish + 1;
if(n2<*istart) *ifinish = *istart - 1;
}
double simpson2(double (*func1)(double),int n, double aa, double bb, int myid, int nproc){
double rslt;
double h,xx;
int j,n1,n2;
int istart,ifinish;
rslt = 0.;
if((n%2) != 0) {
fprintf(stderr,"input error, n must be even number %d\n",n);
exit(9);
}
n1 = 1; n2 = n-1;
equal_load(n1,n2,nproc,myid,&istart,&ifinish);
h = (bb-aa)/(double)n;
if(myid==0) rslt = (func1(aa)+func1(bb));
for(j=istart;j<=ifinish;j++){
xx = aa + h*(double)j;
/*
if((j%2) == 1) {
*/
if((j&1)) {
rslt += 4.L*func1(xx);
}
else {
rslt += 2.L*func1(xx);
}
}
rslt = rslt * h/3.L;
return rslt;
}myparallel.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<sys/time.h>
#include<mpi.h>
int ncall;
typedef enum { FALSE=0, TRUE=1} boolean;
float gettime();
double func(double x){
ncall ++;
return 4.L/(x*x+1.L);
}
double simpson0(double (*func1)(double),int n,double aa,double bb, int ispos, int iepos){
double h,xx,rslt;
int j;
rslt = 0.L;
h = (bb-aa)/(double)n;
for(j = ispos; j <= iepos; j++){
xx = aa + h * (double)j;
if(j%2 == 1) {
rslt += 4.L*func1(xx);
}
else {
rslt += 2.L*func1(xx);
}
}
//rslt = rslt*h/3.L;
return rslt;
}
int main(int argc, char **argv){
double rslt,aa,bb,h,totrslt;
int n, totcall;
double time_start,time_end;
time_start = gettime();
n = 2000000000;
aa = 0.L;
bb = 1.L;
ncall = 0;
int nprocs, myrank;
int q, r, asize, ispos, iepos;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if(myrank == 0 && (n%2) !=0){
fprintf(stderr,"input error, n must be even number %d\n",n);
exit(9);
}
q = (n+1)/nprocs;
r = (n+1)%nprocs;
asize = myrank<r?(q+1):q;
ispos = myrank<r?(q+1)*myrank:(q*myrank+r);
iepos = ispos + asize - 1;
if(myrank == 0) ++ispos;
if(myrank == nprocs-1) --iepos;
rslt = 0.L;
h = (bb-aa)/(double)n;
if(myrank == 0) rslt += (func(aa) + func(bb));
rslt += simpson0(func,n,aa,bb,ispos,iepos);
MPI_Reduce(&rslt, &totrslt, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&ncall, &totcall, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
if(myrank == 0)
totrslt = totrslt*h/3.L;
time_end = gettime();
if(myrank == 0){
printf("%d %18.16g n, rslt,%d\n",n,totrslt,totcall);
printf("Wallclock time %g\n",time_end-time_start);
}
MPI_Finalize();
return 0;
}
struct timeval tv;
float gettime()
{
static int startflag=1;
static double tsecs0, tsecs1;
if( startflag ) {
(void ) gettimeofday(&tv,0);
tsecs0 = tv.tv_sec + tv.tv_usec*1.0e-6;
startflag = 0;
}
(void) gettimeofday(&tv,0);
tsecs1 = tv.tv_sec + tv.tv_usec*1.0e-6;
return ((float) (tsecs1-tsecs0));
}
'Parallel Programming' 카테고리의 다른 글
| KSC 2013 3번 문제 및 답안 (0) | 2016.10.01 |
|---|---|
| KSC 2013 2번 문제 및 답안 (0) | 2016.10.01 |
| 유한차분법(finite difference method)에서 boundary exchange하기 (0) | 2016.09.28 |
| 블록 분할코드 (0) | 2016.09.13 |
| 병렬 컴퓨팅 효율검사 (0) | 2016.09.09 |
댓글