fft.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include "mpi.h"
  5. #define MAX_N 50
  6. #define PI 3.1415926535897932
  7. #define EPS 10E-8
  8. #define V_TAG 99
  9. #define P_TAG 100
  10. #define Q_TAG 101
  11. #define R_TAG 102
  12. #define S_TAG 103
  13. #define S_TAG2 104
  14. typedef enum {FALSE, TRUE}
  15. BOOL;
  16. typedef struct
  17. {
  18. double r;
  19. double i;
  20. } complex_t;
  21. complex_t p[MAX_N], q[MAX_N], s[2*MAX_N], r[2*MAX_N];
  22. complex_t w[2*MAX_N];
  23. int variableNum;
  24. double transTime = 0, totalTime = 0, beginTime;
  25. MPI_Status status;
  26. void comp_add(complex_t* result, const complex_t* c1, const complex_t* c2)
  27. {
  28. result->r = c1->r + c2->r;
  29. result->i = c1->i + c2->i;
  30. }
  31. void comp_multiply(complex_t* result, const complex_t* c1, const complex_t* c2)
  32. {
  33. result->r = c1->r * c2->r - c1->i * c2->i;
  34. result->i = c1->r * c2->i + c2->r * c1->i;
  35. }
  36. /*
  37. * Function: shuffle
  38. * Description: 移动f中从beginPos到endPos位置的元素,使之按位置奇偶
  39. * 重新排列。举例说明:假设数组f,beginPos=2, endPos=5
  40. * 则shuffle函数的运行结果为f[2..5]重新排列,排列后各个
  41. * 位置对应的原f的元素为: f[2],f[4],f[3],f[5]
  42. * Parameters: f为被操作数组首地址
  43. * beginPos, endPos为操作的下标范围
  44. */
  45. void shuffle(complex_t* f, int beginPos, int endPos)
  46. {
  47. int i;
  48. complex_t temp[2*MAX_N];
  49. for(i = beginPos; i <= endPos; i ++)
  50. {
  51. temp[i] = f[i];
  52. }
  53. int j = beginPos;
  54. for(i = beginPos; i <= endPos; i +=2)
  55. {
  56. f[j] = temp[i];
  57. j++;
  58. }
  59. for(i = beginPos +1; i <= endPos; i += 2)
  60. {
  61. f[j] = temp[i];
  62. j++;
  63. }
  64. }
  65. /*
  66. * Function: evaluate
  67. * Description: 对复数序列f进行FFT或者IFFT(由x决定),结果序列为y,
  68. * 产生leftPos 到 rightPos之间的结果元素
  69. * Parameters: f : 原始序列数组首地址
  70. * beginPos : 原始序列在数组f中的第一个下标
  71. * endPos : 原始序列在数组f中的最后一个下标
  72. * x : 存放单位根的数组,其元素为w,w^2,w^3...
  73. * y : 输出序列
  74. * leftPos : 所负责计算输出的y的片断的起始下标
  75. * rightPos : 所负责计算输出的y的片断的终止下标
  76. * totalLength : y的长度
  77. */
  78. void evaluate(complex_t* f, int beginPos, int endPos,
  79. const complex_t* x, complex_t* y,
  80. int leftPos, int rightPos, int totalLength)
  81. {
  82. int i;
  83. if ((beginPos > endPos)||(leftPos > rightPos))
  84. {
  85. printf("Error in use Polynomial!\n");
  86. exit(-1);
  87. }
  88. else if(beginPos == endPos)
  89. {
  90. for(i = leftPos; i <= rightPos; i ++)
  91. {
  92. y[i] = f[beginPos];
  93. }
  94. }
  95. else if(beginPos + 1 == endPos)
  96. {
  97. for(i = leftPos; i <= rightPos; i ++)
  98. {
  99. complex_t temp;
  100. comp_multiply(&temp, &f[endPos], &x[i]);
  101. comp_add(&y[i], &f[beginPos], &temp);
  102. }
  103. }
  104. else
  105. {
  106. complex_t tempX[2*MAX_N],tempY1[2*MAX_N], tempY2[2*MAX_N];
  107. int midPos = (beginPos + endPos)/2;
  108. shuffle(f, beginPos, endPos);
  109. for(i = leftPos; i <= rightPos; i ++)
  110. {
  111. comp_multiply(&tempX[i], &x[i], &x[i]);
  112. }
  113. evaluate(f, beginPos, midPos, tempX, tempY1,
  114. leftPos, rightPos, totalLength);
  115. evaluate(f, midPos+1, endPos, tempX, tempY2,
  116. leftPos, rightPos, totalLength);
  117. for(i = leftPos; i <= rightPos; i ++)
  118. {
  119. complex_t temp;
  120. comp_multiply(&temp, &x[i], &tempY2[i]);
  121. comp_add(&y[i], &tempY1[i], &temp);
  122. }
  123. }
  124. }
  125. /*
  126. * Function: print
  127. * Description: 打印数组元素的实部
  128. * Parameters: f为待打印数组的首地址
  129. * fLength为数组的长度
  130. */
  131. void print(const complex_t* f, int fLength)
  132. {
  133. BOOL isPrint = FALSE;
  134. int i;
  135. /* f[0] */
  136. if (abs(f[0].r) > EPS)
  137. {
  138. printf("%f", f[0].r);
  139. isPrint = TRUE;
  140. }
  141. for(i = 1; i < fLength; i ++)
  142. {
  143. if (f[i].r > EPS)
  144. {
  145. if (isPrint)
  146. printf(" + ");
  147. else
  148. isPrint = TRUE;
  149. printf("%ft^%d", f[i].r, i);
  150. }
  151. else if (f[i].r < - EPS)
  152. {
  153. if(isPrint)
  154. printf(" - ");
  155. else
  156. isPrint = TRUE;
  157. printf("%ft^%d", -f[i].r, i);
  158. }
  159. }
  160. if (isPrint == FALSE)
  161. printf("0");
  162. printf("\n");
  163. }
  164. /*
  165. * Function: myprint
  166. * Description: 完整打印复数数组元素,包括实部和虚部
  167. * Parameters: f为待打印数组的首地址
  168. * fLength为数组的长度
  169. */
  170. void myprint(const complex_t* f, int fLength)
  171. {
  172. int i;
  173. for(i=0;i<fLength;i++)
  174. {
  175. printf("%f+%fi , ", f[i].r, f[i].i);
  176. }
  177. printf("\n");
  178. }
  179. /*
  180. * Function: addTransTime
  181. * Description:累计发送数据所耗费的时间
  182. * Parameters: toAdd为累加的时间
  183. */
  184. void addTransTime(double toAdd)
  185. {
  186. transTime += toAdd;
  187. }
  188. /*
  189. * Function: readFromFile
  190. * Description: 从dataIn.txt读取数据
  191. */
  192. BOOL readFromFile()
  193. {
  194. int i;
  195. FILE* fin = fopen("dataIn.txt", "r");
  196. if (fin == NULL)
  197. {
  198. printf("Cannot find input data file\n"
  199. "Please create a file \"dataIn.txt\"\n"
  200. "2\n"
  201. "1.0 2\n"
  202. "2.0 -1\n"
  203. );
  204. return(FALSE);
  205. }
  206. fscanf(fin, "%d\n", &variableNum);
  207. if ((variableNum < 1)||(variableNum > MAX_N))
  208. {
  209. printf("variableNum out of range!\n");
  210. return(FALSE);
  211. }
  212. for(i = 0; i < variableNum; i ++)
  213. {
  214. fscanf(fin, "%lf", &p[i].r);
  215. p[i].i = 0.0;
  216. }
  217. for(i = 0; i < variableNum; i ++)
  218. {
  219. fscanf(fin, "%lf", &q[i].r);
  220. q[i].i = 0.0;
  221. }
  222. fclose(fin);
  223. printf("Read from data file \"dataIn.txt\"\n");
  224. printf("p(t) = ");
  225. print(p, variableNum);
  226. printf("q(t) = ");
  227. print(q, variableNum);
  228. return(TRUE);
  229. }
  230. /*
  231. * Function: sendOrigData
  232. * Description: 把原始数据发送给其它进程
  233. * Parameters: size为集群中进程的数目
  234. */
  235. void sendOrigData(int size)
  236. {
  237. int i;
  238. for(i = 1; i < size; i ++)
  239. {
  240. MPI_Send(&variableNum, 1, MPI_INT, i, V_TAG, MPI_COMM_WORLD);
  241. MPI_Send(p, variableNum * 2, MPI_DOUBLE, i, P_TAG, MPI_COMM_WORLD);
  242. MPI_Send(q, variableNum * 2, MPI_DOUBLE, i, Q_TAG, MPI_COMM_WORLD);
  243. }
  244. }
  245. /*
  246. * Function: recvOrigData
  247. * Description: 接受原始数据
  248. */
  249. void recvOrigData()
  250. {
  251. MPI_Recv(&variableNum, 1, MPI_INT, 0, V_TAG, MPI_COMM_WORLD, &status);
  252. MPI_Recv(p, variableNum * 2, MPI_DOUBLE, 0, P_TAG, MPI_COMM_WORLD, &status);
  253. MPI_Recv(q, variableNum * 2, MPI_DOUBLE, 0, Q_TAG,MPI_COMM_WORLD, &status);
  254. }
  255. int main(int argc, char *argv[])
  256. {
  257. int rank,size, i;
  258. MPI_Init(&argc,&argv);
  259. MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  260. MPI_Comm_size(MPI_COMM_WORLD,&size);
  261. if(rank == 0)
  262. {
  263. /* 0# 进程从文件dataIn.txt读入多项式p,q的阶数和系数序列 */
  264. if(!readFromFile())
  265. exit(-1);
  266. /* 进程数目太多,造成每个进程平均分配不到一个元素,异常退出 */
  267. if(size > 2*variableNum)
  268. {
  269. printf("Too many Processors , reduce your -np value\n");
  270. MPI_Abort(MPI_COMM_WORLD, 1);
  271. }
  272. beginTime = MPI_Wtime();
  273. /* 0#进程把多项式的阶数、p、q发送给其它进程 */
  274. sendOrigData(size);
  275. /* 累计传输时间 */
  276. addTransTime(MPI_Wtime() - beginTime);
  277. }
  278. else /* 其它进程接收进程0发送来的数据,包括variableNum、数组p和q */
  279. {
  280. recvOrigData();
  281. }
  282. /* 初始化数组w,用于进行傅立叶变换 */
  283. int wLength = 2*variableNum;
  284. for(i = 0; i < wLength; i ++)
  285. {
  286. w[i].r = cos(i*2*PI/wLength);
  287. w[i].i = sin(i*2*PI/wLength);
  288. }
  289. /* 划分各个进程的工作范围 startPos ~ stopPos */
  290. int everageLength = wLength / size;
  291. int moreLength = wLength % size;
  292. int startPos = moreLength + rank * everageLength;
  293. int stopPos = startPos + everageLength - 1;
  294. if(rank == 0)
  295. {
  296. startPos = 0;
  297. stopPos = moreLength+everageLength - 1;
  298. }
  299. /* 对p作FFT,输出序列为s,每个进程仅负责计算出序列中 */
  300. /* 位置为startPos 到 stopPos的元素 */
  301. evaluate(p, 0, variableNum - 1, w, s, startPos, stopPos, wLength);
  302. /* 对q作FFT,输出序列为r,每个进程仅负责计算出序列中 */
  303. /* 位置为startPos 到 stopPos的元素 */
  304. evaluate(q, 0, variableNum - 1, w, r, startPos, stopPos, wLength);
  305. /* s和r作点积,结果保存在s中,同样,每个进程只计算自己范围内的部分 */
  306. for(i = startPos; i <= stopPos ; i ++)
  307. {
  308. complex_t temp;
  309. comp_multiply(&temp, &s[i], &r[i]);
  310. s[i] = temp;
  311. s[i].r /= wLength * 1.0;
  312. s[i].i /= wLength * 1.0;
  313. }
  314. /* 各个进程都把s中自己负责计算出来的部分发送给进程0,并从进程0接收汇总的s */
  315. if (rank > 0)
  316. {
  317. MPI_Send(s + startPos, everageLength * 2, MPI_DOUBLE, 0, S_TAG, MPI_COMM_WORLD);
  318. MPI_Recv(s, wLength * 2, MPI_DOUBLE, 0, S_TAG2, MPI_COMM_WORLD, &status);
  319. }
  320. else
  321. {
  322. /* 进程0接收s片断,向其余进程发送完整的s */
  323. double tempTime = MPI_Wtime();
  324. for(i = 1; i < size; i ++)
  325. {
  326. MPI_Recv(s + moreLength + i * everageLength, everageLength * 2,
  327. MPI_DOUBLE, i, S_TAG, MPI_COMM_WORLD,&status);
  328. }
  329. for(i = 1; i < size; i ++)
  330. {
  331. MPI_Send(s, wLength * 2,
  332. MPI_DOUBLE, i,
  333. S_TAG2, MPI_COMM_WORLD);
  334. }
  335. addTransTime(MPI_Wtime() - tempTime);
  336. }
  337. /* swap(w[i],w[(wLength-i)%wLength]) */
  338. /* 重新设置w,用于作逆傅立叶变换 */
  339. complex_t temp;
  340. for(i = 1; i < wLength/2; i ++)
  341. {
  342. temp = w[i];
  343. w[i] = w[wLength - i];
  344. w[wLength - i] = temp;
  345. }
  346. /* 各个进程对s作逆FFT,输出到r的相应部分 */
  347. evaluate(s, 0, wLength - 1, w, r, startPos, stopPos, wLength);
  348. /* 各进程把自己负责的部分的r的片断发送到进程0 */
  349. if (rank > 0)
  350. {
  351. MPI_Send(r + startPos, everageLength * 2, MPI_DOUBLE,
  352. 0,R_TAG, MPI_COMM_WORLD);
  353. }
  354. else
  355. {
  356. /* 进程0接收各个片断得到完整的r,此时r就是两多项式p,q相乘的结果多项式了 */
  357. double tempTime = MPI_Wtime();
  358. for(i = 1; i < size; i ++)
  359. {
  360. MPI_Recv((r+moreLength+i*everageLength), everageLength * 2,
  361. MPI_DOUBLE, i, R_TAG, MPI_COMM_WORLD, &status);
  362. }
  363. totalTime = MPI_Wtime();
  364. addTransTime(totalTime - tempTime);
  365. totalTime -= beginTime;
  366. /* 输出结果信息以及时间统计信息 */
  367. printf("\nAfter FFT r(t)=p(t)q(t)\n");
  368. printf("r(t) = ");
  369. print(r, wLength - 1);
  370. printf("\nUse prossor size = %d\n", size);
  371. printf("Total running time = %f(s)\n", totalTime);
  372. printf("Distribute data time = %f(s)\n", transTime);
  373. printf("Parallel compute time = %f(s)\n", totalTime - transTime);
  374. }
  375. MPI_Finalize();
  376. }