123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "mpi.h"
- #define MAX_N 50
- #define PI 3.1415926535897932
- #define EPS 10E-8
- #define V_TAG 99
- #define P_TAG 100
- #define Q_TAG 101
- #define R_TAG 102
- #define S_TAG 103
- #define S_TAG2 104
- typedef enum {FALSE, TRUE}
- BOOL;
- typedef struct
- {
- double r;
- double i;
- } complex_t;
- complex_t p[MAX_N], q[MAX_N], s[2*MAX_N], r[2*MAX_N];
- complex_t w[2*MAX_N];
- int variableNum;
- double transTime = 0, totalTime = 0, beginTime;
- MPI_Status status;
- void comp_add(complex_t* result, const complex_t* c1, const complex_t* c2)
- {
- result->r = c1->r + c2->r;
- result->i = c1->i + c2->i;
- }
- void comp_multiply(complex_t* result, const complex_t* c1, const complex_t* c2)
- {
- result->r = c1->r * c2->r - c1->i * c2->i;
- result->i = c1->r * c2->i + c2->r * c1->i;
- }
- /*
- * Function: shuffle
- * Description: 移动f中从beginPos到endPos位置的元素,使之按位置奇偶
- * 重新排列。举例说明:假设数组f,beginPos=2, endPos=5
- * 则shuffle函数的运行结果为f[2..5]重新排列,排列后各个
- * 位置对应的原f的元素为: f[2],f[4],f[3],f[5]
- * Parameters: f为被操作数组首地址
- * beginPos, endPos为操作的下标范围
- */
- void shuffle(complex_t* f, int beginPos, int endPos)
- {
- int i;
- complex_t temp[2*MAX_N];
- for(i = beginPos; i <= endPos; i ++)
- {
- temp[i] = f[i];
- }
- int j = beginPos;
- for(i = beginPos; i <= endPos; i +=2)
- {
- f[j] = temp[i];
- j++;
- }
- for(i = beginPos +1; i <= endPos; i += 2)
- {
- f[j] = temp[i];
- j++;
- }
- }
- /*
- * Function: evaluate
- * Description: 对复数序列f进行FFT或者IFFT(由x决定),结果序列为y,
- * 产生leftPos 到 rightPos之间的结果元素
- * Parameters: f : 原始序列数组首地址
- * beginPos : 原始序列在数组f中的第一个下标
- * endPos : 原始序列在数组f中的最后一个下标
- * x : 存放单位根的数组,其元素为w,w^2,w^3...
- * y : 输出序列
- * leftPos : 所负责计算输出的y的片断的起始下标
- * rightPos : 所负责计算输出的y的片断的终止下标
- * totalLength : y的长度
- */
- void evaluate(complex_t* f, int beginPos, int endPos,
- const complex_t* x, complex_t* y,
- int leftPos, int rightPos, int totalLength)
- {
- int i;
- if ((beginPos > endPos)||(leftPos > rightPos))
- {
- printf("Error in use Polynomial!\n");
- exit(-1);
- }
- else if(beginPos == endPos)
- {
- for(i = leftPos; i <= rightPos; i ++)
- {
- y[i] = f[beginPos];
- }
- }
- else if(beginPos + 1 == endPos)
- {
- for(i = leftPos; i <= rightPos; i ++)
- {
- complex_t temp;
- comp_multiply(&temp, &f[endPos], &x[i]);
- comp_add(&y[i], &f[beginPos], &temp);
- }
- }
- else
- {
- complex_t tempX[2*MAX_N],tempY1[2*MAX_N], tempY2[2*MAX_N];
- int midPos = (beginPos + endPos)/2;
- shuffle(f, beginPos, endPos);
- for(i = leftPos; i <= rightPos; i ++)
- {
- comp_multiply(&tempX[i], &x[i], &x[i]);
- }
- evaluate(f, beginPos, midPos, tempX, tempY1,
- leftPos, rightPos, totalLength);
- evaluate(f, midPos+1, endPos, tempX, tempY2,
- leftPos, rightPos, totalLength);
- for(i = leftPos; i <= rightPos; i ++)
- {
- complex_t temp;
- comp_multiply(&temp, &x[i], &tempY2[i]);
- comp_add(&y[i], &tempY1[i], &temp);
- }
- }
- }
- /*
- * Function: print
- * Description: 打印数组元素的实部
- * Parameters: f为待打印数组的首地址
- * fLength为数组的长度
- */
- void print(const complex_t* f, int fLength)
- {
- BOOL isPrint = FALSE;
- int i;
- /* f[0] */
- if (abs(f[0].r) > EPS)
- {
- printf("%f", f[0].r);
- isPrint = TRUE;
- }
- for(i = 1; i < fLength; i ++)
- {
- if (f[i].r > EPS)
- {
- if (isPrint)
- printf(" + ");
- else
- isPrint = TRUE;
- printf("%ft^%d", f[i].r, i);
- }
- else if (f[i].r < - EPS)
- {
- if(isPrint)
- printf(" - ");
- else
- isPrint = TRUE;
- printf("%ft^%d", -f[i].r, i);
- }
- }
- if (isPrint == FALSE)
- printf("0");
- printf("\n");
- }
- /*
- * Function: myprint
- * Description: 完整打印复数数组元素,包括实部和虚部
- * Parameters: f为待打印数组的首地址
- * fLength为数组的长度
- */
- void myprint(const complex_t* f, int fLength)
- {
- int i;
- for(i=0;i<fLength;i++)
- {
- printf("%f+%fi , ", f[i].r, f[i].i);
- }
- printf("\n");
- }
- /*
- * Function: addTransTime
- * Description:累计发送数据所耗费的时间
- * Parameters: toAdd为累加的时间
- */
- void addTransTime(double toAdd)
- {
- transTime += toAdd;
- }
- /*
- * Function: readFromFile
- * Description: 从dataIn.txt读取数据
- */
- BOOL readFromFile()
- {
- int i;
- FILE* fin = fopen("dataIn.txt", "r");
- if (fin == NULL)
- {
- printf("Cannot find input data file\n"
- "Please create a file \"dataIn.txt\"\n"
- "2\n"
- "1.0 2\n"
- "2.0 -1\n"
- );
- return(FALSE);
- }
- fscanf(fin, "%d\n", &variableNum);
- if ((variableNum < 1)||(variableNum > MAX_N))
- {
- printf("variableNum out of range!\n");
- return(FALSE);
- }
- for(i = 0; i < variableNum; i ++)
- {
- fscanf(fin, "%lf", &p[i].r);
- p[i].i = 0.0;
- }
- for(i = 0; i < variableNum; i ++)
- {
- fscanf(fin, "%lf", &q[i].r);
- q[i].i = 0.0;
- }
- fclose(fin);
- printf("Read from data file \"dataIn.txt\"\n");
- printf("p(t) = ");
- print(p, variableNum);
- printf("q(t) = ");
- print(q, variableNum);
- return(TRUE);
- }
- /*
- * Function: sendOrigData
- * Description: 把原始数据发送给其它进程
- * Parameters: size为集群中进程的数目
- */
- void sendOrigData(int size)
- {
- int i;
- for(i = 1; i < size; i ++)
- {
- MPI_Send(&variableNum, 1, MPI_INT, i, V_TAG, MPI_COMM_WORLD);
- MPI_Send(p, variableNum * 2, MPI_DOUBLE, i, P_TAG, MPI_COMM_WORLD);
- MPI_Send(q, variableNum * 2, MPI_DOUBLE, i, Q_TAG, MPI_COMM_WORLD);
- }
- }
- /*
- * Function: recvOrigData
- * Description: 接受原始数据
- */
- void recvOrigData()
- {
- MPI_Recv(&variableNum, 1, MPI_INT, 0, V_TAG, MPI_COMM_WORLD, &status);
- MPI_Recv(p, variableNum * 2, MPI_DOUBLE, 0, P_TAG, MPI_COMM_WORLD, &status);
- MPI_Recv(q, variableNum * 2, MPI_DOUBLE, 0, Q_TAG,MPI_COMM_WORLD, &status);
- }
- int main(int argc, char *argv[])
- {
- int rank,size, i;
- MPI_Init(&argc,&argv);
- MPI_Comm_rank(MPI_COMM_WORLD,&rank);
- MPI_Comm_size(MPI_COMM_WORLD,&size);
- if(rank == 0)
- {
- /* 0# 进程从文件dataIn.txt读入多项式p,q的阶数和系数序列 */
- if(!readFromFile())
- exit(-1);
- /* 进程数目太多,造成每个进程平均分配不到一个元素,异常退出 */
- if(size > 2*variableNum)
- {
- printf("Too many Processors , reduce your -np value\n");
- MPI_Abort(MPI_COMM_WORLD, 1);
- }
- beginTime = MPI_Wtime();
- /* 0#进程把多项式的阶数、p、q发送给其它进程 */
- sendOrigData(size);
- /* 累计传输时间 */
- addTransTime(MPI_Wtime() - beginTime);
- }
- else /* 其它进程接收进程0发送来的数据,包括variableNum、数组p和q */
- {
- recvOrigData();
- }
- /* 初始化数组w,用于进行傅立叶变换 */
- int wLength = 2*variableNum;
- for(i = 0; i < wLength; i ++)
- {
- w[i].r = cos(i*2*PI/wLength);
- w[i].i = sin(i*2*PI/wLength);
- }
- /* 划分各个进程的工作范围 startPos ~ stopPos */
- int everageLength = wLength / size;
- int moreLength = wLength % size;
- int startPos = moreLength + rank * everageLength;
- int stopPos = startPos + everageLength - 1;
- if(rank == 0)
- {
- startPos = 0;
- stopPos = moreLength+everageLength - 1;
- }
- /* 对p作FFT,输出序列为s,每个进程仅负责计算出序列中 */
- /* 位置为startPos 到 stopPos的元素 */
- evaluate(p, 0, variableNum - 1, w, s, startPos, stopPos, wLength);
- /* 对q作FFT,输出序列为r,每个进程仅负责计算出序列中 */
- /* 位置为startPos 到 stopPos的元素 */
- evaluate(q, 0, variableNum - 1, w, r, startPos, stopPos, wLength);
- /* s和r作点积,结果保存在s中,同样,每个进程只计算自己范围内的部分 */
- for(i = startPos; i <= stopPos ; i ++)
- {
- complex_t temp;
- comp_multiply(&temp, &s[i], &r[i]);
- s[i] = temp;
- s[i].r /= wLength * 1.0;
- s[i].i /= wLength * 1.0;
- }
- /* 各个进程都把s中自己负责计算出来的部分发送给进程0,并从进程0接收汇总的s */
- if (rank > 0)
- {
- MPI_Send(s + startPos, everageLength * 2, MPI_DOUBLE, 0, S_TAG, MPI_COMM_WORLD);
- MPI_Recv(s, wLength * 2, MPI_DOUBLE, 0, S_TAG2, MPI_COMM_WORLD, &status);
- }
- else
- {
- /* 进程0接收s片断,向其余进程发送完整的s */
- double tempTime = MPI_Wtime();
- for(i = 1; i < size; i ++)
- {
- MPI_Recv(s + moreLength + i * everageLength, everageLength * 2,
- MPI_DOUBLE, i, S_TAG, MPI_COMM_WORLD,&status);
- }
- for(i = 1; i < size; i ++)
- {
- MPI_Send(s, wLength * 2,
- MPI_DOUBLE, i,
- S_TAG2, MPI_COMM_WORLD);
- }
- addTransTime(MPI_Wtime() - tempTime);
- }
- /* swap(w[i],w[(wLength-i)%wLength]) */
- /* 重新设置w,用于作逆傅立叶变换 */
- complex_t temp;
- for(i = 1; i < wLength/2; i ++)
- {
- temp = w[i];
- w[i] = w[wLength - i];
- w[wLength - i] = temp;
- }
- /* 各个进程对s作逆FFT,输出到r的相应部分 */
- evaluate(s, 0, wLength - 1, w, r, startPos, stopPos, wLength);
- /* 各进程把自己负责的部分的r的片断发送到进程0 */
- if (rank > 0)
- {
- MPI_Send(r + startPos, everageLength * 2, MPI_DOUBLE,
- 0,R_TAG, MPI_COMM_WORLD);
- }
- else
- {
- /* 进程0接收各个片断得到完整的r,此时r就是两多项式p,q相乘的结果多项式了 */
- double tempTime = MPI_Wtime();
- for(i = 1; i < size; i ++)
- {
- MPI_Recv((r+moreLength+i*everageLength), everageLength * 2,
- MPI_DOUBLE, i, R_TAG, MPI_COMM_WORLD, &status);
- }
- totalTime = MPI_Wtime();
- addTransTime(totalTime - tempTime);
- totalTime -= beginTime;
- /* 输出结果信息以及时间统计信息 */
- printf("\nAfter FFT r(t)=p(t)q(t)\n");
- printf("r(t) = ");
- print(r, wLength - 1);
- printf("\nUse prossor size = %d\n", size);
- printf("Total running time = %f(s)\n", totalTime);
- printf("Distribute data time = %f(s)\n", transTime);
- printf("Parallel compute time = %f(s)\n", totalTime - transTime);
- }
- MPI_Finalize();
- }
|