燕山大学多核程序设计实验报告.pdf
燕山大学多核程序设计实验报燕山大学多核程序设计实验报告告实验一实验一 WindowsWindows 多线程编程多线程编程一、实验目的与要求一、实验目的与要求了解了解 windowswindows 多线程编程机制多线程编程机制掌握线程同步的方法掌握线程同步的方法二、实验环境和软件二、实验环境和软件Windows XPWindows XPVC 6.0VC 6.0三、实验内容三、实验内容创建线程:创建线程:HANDLE CreateThread(HANDLE CreateThread(LPSECURITY_ATTRIBUTESLPSECURITY_ATTRIBUTESlpThreadAttributes,lpThreadAttributes,SIZE_T dwStackSize,SIZE_T dwStackSize,LPTHREAD_START_ROUTINELPTHREAD_START_ROUTINElpStartAddress,lpStartAddress,LPVOID lpParameter,LPVOID lpParameter,DWORD dwCreationFlags,DWORD dwCreationFlags,LPDWORD lpThreadIdLPDWORD lpThreadId););四、实验程序四、实验程序#includestdafx.h#includestdafx.h#include#include#include#include#include#include#include#includeusing namespace std;using namespace std;void ThreadFrunc1(PVOID param)void ThreadFrunc1(PVOID param)while(1)while(1)Sleep(1000);Sleep(1000);3 3coutThiscoutThisThreadFrunc1endl;ThreadFrunc1endl;void ThreadFrunc2(PVOID param)void ThreadFrunc2(PVOID param)while(1)while(1)Sleep(1000);Sleep(1000);coutThiscoutThisThreadFrunc2endl;ThreadFrunc2endl;int main()int main()int i=0;int i=0;isisisiskjjkjj_beginthread(ThreadFrunc1,0,NUL_beginthread(ThreadFrunc1,0,NULL);L);4 4_beginthread(ThreadFrunc2,0,NUL_beginthread(ThreadFrunc2,0,NULL);L);Sleep(3000);Sleep(3000);coutendendl;coutendendl;return 0;return 0;实验结果实验结果实验二实验二 蒙特卡罗法求蒙特卡罗法求 PIPI一、实验目的和要求一、实验目的和要求蒙特卡洛算法可理解为通过大量实验,蒙特卡洛算法可理解为通过大量实验,模拟实际行为,模拟实际行为,来收集统计数据。来收集统计数据。本例本例中,中,算法随机产生一系列点,算法随机产生一系列点,模拟这些模拟这些点落在如下图所示的正方形区域内的点落在如下图所示的正方形区域内的5 5情况。其几何解释如下情况。其几何解释如下1Y轴X 轴1图图 1 1如图如图 1 1 所示,正方形边长为所示,正方形边长为 1 1,左下顶,左下顶点与原点重合,两边分别与点与原点重合,两边分别与 x x,y y 轴重轴重合。曲线为合。曲线为 1/41/4 圆弧,圆心位于原点,圆弧,圆心位于原点,与正方形左下定点重合,半径为与正方形左下定点重合,半径为 1 1。正。正方方 形形 面面 积积S1=1S1=1,圆圆 弧弧 内内 面面 积积121S2=S2=4r4。算法模拟大量点随机落算法模拟大量点随机落在此正方形区域内,在此正方形区域内,落在圆弧内的点的落在圆弧内的点的数量(数量(n2n2)与点的总数()与点的总数(n1n1)的比例与)的比例与面积成正比关系。即面积成正比关系。即6 6countcountcount,则,则4n3.23.2 并行算法描述并行算法描述算法步骤:算法步骤:1 1、确定需要产生的点的个数、确定需要产生的点的个数 n n,参与,参与运行的处理器数运行的处理器数 m m;2 2、对每一个处理器,生成两个随机数、对每一个处理器,生成两个随机数x x,y y,范围,范围00,11;3 3、判断两个随机数、判断两个随机数x x,y y 是否满足是否满足x2 y21;4 4、若满足,则变量、若满足,则变量 COUNTi+COUNTi+;5 5、重复步骤、重复步骤 2-42-4,直至每个处理器均,直至每个处理器均生成生成 n/mn/m 个随机点;个随机点;6 6、收集、收集 COUNTiCOUNTi 的值,并累加至变量的值,并累加至变量COUNTCOUNT 中,此即为随机点落在圆弧内的中,此即为随机点落在圆弧内的数量;数量;7 7、通过(、通过(2 2)式计算)式计算的值。的值。3.33.3 并行算法在并行算法在 WindowsWindows 下的一个例子下的一个例子#include#include#include#include#include#include/#include/#include#include#include#include#include#include#includeusing namespace std;using namespace std;HANDLE evFinish;HANDLE evFinish;long cs=0;/long cs=0;/总循环次数总循环次数long count=0;/long count=0;/主线程有效次数主线程有效次数long count_thread=0;/threadlong count_thread=0;/thread 线程线程有效次数有效次数time_t start,finish;/time_t start,finish;/定义开始结定义开始结束时间束时间/thread/thread 线程计算量为总数的一半线程计算量为总数的一半DWORD WINAPI thread(LPVOID param)DWORD WINAPI thread(LPVOID param)int i=0;int i=0;1 10 0double x,y;double x,y;for(i=0;ics/2;i+)for(i=0;ics/2;i+)x=(longx=(longy=(longy=(longdouble)rand()/(longdouble)rand()/(longdouble)rand()/(longdouble)rand()/(longdouble)RAND_MAX;double)RAND_MAX;double)RAND_MAX;double)RAND_MAX;if(x*x+y*y)=1)if(x*x+y*y)=1)count_thread+;count_thread+;/printf(/printf(副副%d,i);%d,i);SetEvent(evFinish);SetEvent(evFinish);return 0;return 0;/主线程计算量为总数的一半主线程计算量为总数的一半int main(void)int main(void)1 11 1evFinish=CreateEvent(NULL,FALSE,FevFinish=CreateEvent(NULL,FALSE,FALSE,NULL);ALSE,NULL);printf(printf(请输入总循环次数请输入总循环次数:);:);scanf(%d,&cs);scanf(%d,&cs);cs*=1000000;cs*=1000000;srand(unsigned)time(NULL)srand(unsigned)time(NULL);/;/用时间作随机数种子用时间作随机数种子 start=time(NULL);start=time(NULL);/记记录录开开始始时间时间HANDLEHANDLEid=CreateThread(NULL,0,thread,NULid=CreateThread(NULL,0,thread,NULL,0,NULL);L,0,NULL);/创建创建 threadthread 线程线程int i=0;int i=0;double x,y;double x,y;for(i=0;ics/2;i+)for(i=0;ics/2;i+)x=(longx=(longdouble)rand()/(longdouble)rand()/(longdouble)RAND_MAX;double)RAND_MAX;1 12 2y=(longy=(longdouble)rand()/(longdouble)rand()/(longdouble)RAND_MAX;double)RAND_MAX;if(x*x+y*y)=1)if(x*x+y*y)=1)count+;count+;/p printf(rintf(主主%d,i);%d,i);/printf(count%d,count);/printf(count%d,count);WaitForSingleObject(evFinish,INFIWaitForSingleObject(evFinish,INFINITE);/NITE);/两线程同步两线程同步count+=count_thread;count+=count_thread;finish=time(NULL);/finish=time(NULL);/记录结束记录结束时间时间printf(printf(并行情况:并行情况:nn);nn);printf(printf(用用时时=%f=%f秒秒n,difftime(finish,start);n,difftime(finish,start);/计算时间差计算时间差 printf(printf(总共的循环总共的循环次数次数=%d=%d 次次n,cs);n,cs);printf(printf(线线程程有有效效次次数数=%d=%d 次次1 13 3n,count);n,count);printf(pi=printf(pi=printf(printf(串行行情况:串行行情况:n);n);count=0;count=0;start=time(NULL);/start=time(NULL);/记录开始时间记录开始时间for(i=0;ics;i+)for(i=0;ics;i+)x=(longx=(longy=(longy=(longdouble)rand()/(longdouble)rand()/(longdouble)rand()/(longdouble)rand()/(longdouble)RAND_MAX;double)RAND_MAX;double)RAND_MAX;double)RAND_MAX;if(x*x+y*y)=1)if(x*x+y*y)=1)count+;count+;/p printf(rintf(主主%d,i);%d,i);/printf(count%d,count);/printf(count%d,count);finish=time(NULL);/finish=time(NULL);/记录结束时记录结束时1 14 4%f%fn,4*(double)count/(double)cs);n,4*(double)count/(double)cs);间间 printf(printf(用用时时=%f=%f秒秒n,difftime(finish,start);n,difftime(finish,start);printf(printf(总总共共的的循循环环次次数数=%d=%d 次次n,cs);n,cs);printf(printf(线线程程有有效效次次数数=%d=%d 次次n,count);n,count);printf(pi=printf(pi=return(0);return(0);实验结果:实验结果:测试数据集合:测试数据集合:由随机数函数产生的数由随机数函数产生的数据集合据集合%f%fn,4*(double)count/(double)cs);n,4*(double)count/(double)cs);1 15 5实验三实验三 并行排序并行排序一、实验目的与要求一、实验目的与要求在单核计算环境中,在单核计算环境中,排序算法关注的核排序算法关注的核心问题是怎样减少要排序数据之间的心问题是怎样减少要排序数据之间的比较次数或算法所需要的内存空间。比较次数或算法所需要的内存空间。在多核计算环境中,在多核计算环境中,每个核以线程为执每个核以线程为执行单元,行单元,排序程序可以通过生成相互协排序程序可以通过生成相互协1 16 6作的线程来完成排序。作的线程来完成排序。与单核计算环境与单核计算环境不同的是,不同的是,在多核计算环境中更关注数在多核计算环境中更关注数据集的合理划分,据集的合理划分,更致力于识别可并行更致力于识别可并行执行的任务。执行的任务。一旦完成这些工作,一旦完成这些工作,程序程序设计上就可以生成对应的线程去执行设计上就可以生成对应的线程去执行任务。任务。理论上,理论上,基于相同的串行算法和基于相同的串行算法和相同的相同的 cachecache 命中率,命中率,多核计算速度可多核计算速度可以无限接近单核计算速度的以无限接近单核计算速度的 P P 倍,倍,其中其中P P 为核的数目。为核的数目。多核上的并行排序算法所面临的问题多核上的并行排序算法所面临的问题在于:在于:1.1.未未排序的数据集合理划分到每个线排序的数据集合理划分到每个线程后,程后,最后怎么汇合,最后怎么汇合,形成完整的排好形成完整的排好序的数据集呢?序的数据集呢?2.2.怎怎么保证可并行执行的线程的数目么保证可并行执行的线程的数目和核的数目相等或稍微多于核的数目,和核的数目相等或稍微多于核的数目,同时也保证这些线程之间的工作量也同时也保证这些线程之间的工作量也尽可能的相同呢?尽可能的相同呢?1 17 7在这个实验中,串行的算法采用标准在这个实验中,串行的算法采用标准 C C语言库中的快速排序函数。语言库中的快速排序函数。并行算法中,并行算法中,先将要处理的数据集均等先将要处理的数据集均等的分到每个线程中,的分到每个线程中,并使用并使用 C C 语言库中语言库中的快速排序函数各自排序。的快速排序函数各自排序。然后所有线然后所有线程开始根据相同的数对自己的数据集程开始根据相同的数对自己的数据集进行划分,进行划分,这个数是依据一定的方法选这个数是依据一定的方法选出来的(详见并行算法描述)出来的(详见并行算法描述)。每个线。每个线程的数据集都会被分成程的数据集都会被分成 K K 份,份,(其中其中 P=P=K P2K P2,P P 为核的数目)为核的数目),每份将被称,每份将被称为一桶。很显然这个过程选出了为一桶。很显然这个过程选出了 K K 个个数,这些数将被成为数,这些数将被成为 bound_value,bound_value,记记为为 X1,X2,X3 X1,X2,X3 XK XK。最后每个线。最后每个线程中小于或等于程中小于或等于 X1X1 的数会被一个独立的数会被一个独立的线程去归并排序,同样小于或等于的线程去归并排序,同样小于或等于X2X2 的数也会被另外一个独立的线程去的数也会被另外一个独立的线程去归并排序,依次类推,直到排好序。归并排序,依次类推,直到排好序。需要指出的是:需要指出的是:这个并行版本最消耗时这个并行版本最消耗时1 18 8间的部分是一开始每个线程各自的排间的部分是一开始每个线程各自的排序,时间为:序,时间为:O O(nlogn);不过其数据划;不过其数据划分和线程生成也相对简单。分和线程生成也相对简单。最后的归并最后的归并排序所需时间是线性增长的,排序所需时间是线性增长的,即:即:O O(n),因此即使在最后归并部分线程执行的因此即使在最后归并部分线程执行的任务已经是不均衡的,任务已经是不均衡的,也不会对整个程也不会对整个程序的性能产生很大的影响。序的性能产生很大的影响。二、实验环境和软件二、实验环境和软件编译器:编译器:MicrosoftMicrosoft VisualVisual StudioStudio C+C+6.06.0操作系统:操作系统:Windows XPWindows XP三、实验内容三、实验内容3.13.1 并行算法描述并行算法描述算法算法:1 19 9将原始待排序的数据分成将原始待排序的数据分成 P P 等份,等份,每个每个处理器上对处理器上对 N0N0 个数据进行排序,称每个数据进行排序,称每个被排序后的子集为个被排序后的子集为 B0,B0,Bp-1,Bp-1Remain_data=NRemain_data=N,设定第,设定第 0 0 组归并起始组归并起始位置全部为位置全部为 0,i=00,i=0,设置第,设置第 0 0 组在目组在目标数组中的起始位置为标数组中的起始位置为 0 0循环直至循环直至 remian_dataL(L=N0/P)remian_dataL(L=N0/P)3.13.1 选取所有子集中起始位置后续选取所有子集中起始位置后续L L个元素的最小值个元素的最小值 bound_valuebound_value,并获得,并获得bound_valuebound_value 的桶号的桶号 bucketbucket3.23.2 在所有子集中从起始位置到后续在所有子集中从起始位置到后续 L L个元素中选取边界位置,个元素中选取边界位置,使得边界位置使得边界位置的的 最最 后后 一一 个个 元元 素素 小小 于于 或或 等等 于于bound_valuebound_value,而边界位置后的第一元,而边界位置后的第一元素大于素大于 bound_valuebound_value。3.33.3 记录所有的边界位置,记录所有的边界位置,并设置所有并设置所有第第 i i1 1 组的起始位置为第组的起始位置为第 i i 组的起始组的起始位置加上边界位置位置加上边界位置2 20 03.43.4 累积所有边界值,累积所有边界值,得到该归并组的得到该归并组的大小大小3.53.5 根据归并组大小和本组起始位置根据归并组大小和本组起始位置计算第计算第 i+1i+1 组在目标数组中的起始位组在目标数组中的起始位置。置。4 4、设置最后一个归并组的边界为、设置最后一个归并组的边界为 N0N05 5、对所有归并组进行并行、对所有归并组进行并行 P P 路归并排路归并排序。序。四、实验步骤四、实验步骤说明:说明:A AP P 和多核处理器的数目相同。比如和多核处理器的数目相同。比如是双核的,那么是双核的,那么 P P 2 2;B BRemain_dataRemain_data 是每个线程处理的数是每个线程处理的数据集中还没有被据集中还没有被 X1,X2,X3X1,X2,X3划分划分过的数据集的总数目。比如,根过的数据集的总数目。比如,根据据 X1X1 每个线程划分出来的数据集为每个线程划分出来的数据集为2 21 1x x,y y,z z,那么那么 Remain_dataRemain_datan n x x y y z z.并行算法在并行算法在 WindowsWindows 下的一个例子下的一个例子#include#include#include#include#include#include#include#include#include#include#include#include#ifndef _BASIC_SORT_H#ifndef _BASIC_SORT_H#define _BASIC_SORT_H#define _BASIC_SORT_H#ifndef _SORT_P#ifndef _SORT_P#define _SORT_P#define _SORT_Pvoid*sort(void*parameter);void*sort(void*parameter);void generate_data(int*a,int n);void generate_data(int*a,int n);void sort_s(int*a,int n);void sort_s(int*a,int n);void view_data(int*a,int n);void view_data(int*a,int n);int check_data_sort(int*a,int n);int check_data_sort(int*a,int n);2 22 2intintcompare(compare(constconstvoidvoid*arg1,*arg1,const void*arg2);const void*arg2);#define MILLION 1000000L#define MILLION 1000000L#define P 2#define P 2#define N0 4332539#define N0 4332539/#define N0 1000000/#define N0 1000000#define N N0*P#define N N0*P#define L N0/P#define L N0/Pvoid sort_p(int*d,int*b);void sort_p(int*d,int*b);time_t start,finish;/time_t start,finish;/定义开始结定义开始结束时间束时间struct merge /struct merge /归并结构归并结构int beginP;/int beginP;/数组数组 beginbeginint countP;/int countP;/数组数组 countcountint merge_size;/int merge_size;/归并大小归并大小int global_pos;/int global_pos;/全局位置全局位置int merged;/int merged;/归并是否完归并是否完成成2 23 3;struct arg_merge_data /struct arg_merge_data /归并归并数据结构数据结构int*d;/int*d;/数组的指数组的指针针struct merge*mp;/struct merge*mp;/归并结构归并结构int*b;/int*b;/整数整数 b bint k;int k;struct arg_merge_data*tmp2;struct arg_merge_data*tmp2;struct forsortstruct forsortint*d;int*d;int k;int k;struct forsort forsortaP;struct forsort forsortaP;intintfind_bound_value(intfind_bound_value(int*d,struct merge*mp,int*bucket);*d,struct merge*mp,int*bucket);int find_min(int*d,struct mergeint find_min(int*d,struct merge2 24 4*mp,int*bucket);*mp,int*bucket);voidvoidfind_bound(intfind_bound(int*d,struct*d,structmergemergevoidvoid*mp,int*mp,intbucket,intbucket,intbound_value);bound_value);do_last_merge_block(structdo_last_merge_block(structmerge*mp);merge*mp);void merge_data(void*arg);void merge_data(void*arg);voidvoidview_merge(intview_merge(int*d,struct*d,structmerge*mp,int last_merge_block);merge*mp,int last_merge_block);int start_time();int start_time();int diff_time();int diff_time();#endif#endif#endif#endifint k;int k;HANDLE SwaitP;HANDLE SwaitP;HANDLE PwaitP;HANDLE PwaitP;HANDLE pthreadP;HANDLE pthreadP;HANDLE qthreadP;HANDLE qthreadP;2 25 5extern int*dP;extern int*dP;/voidvoidgenerate_data(intgenerate_data(int*a,*a,intintn)/n)/产生数据产生数据int i;int i;for(i=0;in;i+)for(i=0;in;i+)ai=rand()%10000;ai=rand()%10000;/产生数组产生数组 a a 有有 n n 个元素个元素 for(i=0;iP;i+)for(i=0;ik);/=,forsortb-k);/=2 27 7sort_s(intsort_s(int*a,*a,intintn)/n)/快排快排=int kk=forsortb-k;int kk=forsortb-k;qsort(/*(void*)*/forsortb-d,qsort(/*(void*)*/forsortb-d,N0,sizeof(int),compare);N0,sizeof(int),compare);SetEvent(Swaitkk);/printf(SetEvent(Swaitkk);/printf(n%d,kk);n%d,kk);return(void*)0;return(void*)0;/void view_data(int*a,int n)void view_data(int*a,int n)int i=n,j;int i=n,j;int index=0;int index=0;while(iN0)while(iN0)for(j=0;jN0;j+)for(j=0;j0;i-)for(;i0;i-)/输出输出 aiai中中 N0N0 后面的个数后面的个数printf(%dt,aindex+);printf(%dt,aindex+);printf(n);printf(n);/intintcheck_data_sort(intcheck_data_sort(int*a,int*a,intn)/n)/找出不服和大小顺序的位置找出不服和大小顺序的位置int i;int i;for(i=0;in-1;i+)for(i=0;iai+1)break;if(aiai+1)break;return i;return i;/intintcompare(compare(constconstvoidvoid*arg1,*arg1,const void*arg2)/const void*arg2)/返回返回 arg1arg1 与与arg2arg2 的差的差intint*)arg2;*)arg2;return a-b;return a-b;/int aN;/data for parallel sortint aN;/data for parallel sort3 30 0a=*(inta=*(int*)arg1,b=*(int*)arg1,b=*(intint bN;/the result of parallelint bN;/the result of parallelsortsortint*dP;/for parallel sortint*dP;/for parallel sortint sN;/data for serial sortint sN;/data for serial sortstruct merge m_listP*P;/recordstruct merge m_listP*P;/recordof partitionof partitionint merge_block;/the number ofint merge_block;/the number ofpartitionpartitionDWORD thr_idP*P;DWORD thr_idP*P;longlong timedif;/timedif;/forfor estimateestimate thetheexection timeexection time/struct timeval end;/./struct timeval end;/./struct timeval start;/./struct timeval start;/.void inite()void inite()int i;int i;/forsorta=(struct/forsorta=(structcalloc(P,calloc(P,forsortforsort*)*)sizeofsizeof3 31 1(struct(structforsort);forsort);for(i=0;iP;i+)for(i=0;iP;i+)Swaiti=CreateEvent(NULL,FALSESwaiti=CreateEvent(NULL,FALSE,FALSE,NULL);,FALSE,NULL);Pwaiti=CreateEvent(NULL,FALSEPwaiti=CreateEvent(NULL,FALSE,FALSE,NULL);,FALSE,NULL);/*/*f for(int j=0;jP;j+)or(int j=0;jP;j+)forsortai.dj=dj;forsortai.dj=dj;/printf(forsorta%d.d%d=%dnprintf(forsorta%d.d%d=%dn,i,j,forsortai.dj);,i,j,forsortai.dj);*/*/3 32 2 void main()void main()int data;int data;int i;int i;generate_data(a,N);/generate_data(a,N);/产生数组产生数组ananfor(i=0;iN;i+)/for(i=0;ib%dn,data,datprintf(b%db%dn,data,data+1);a+1);/intintstart_time()start_time()/记录记录 开开始始时时间间函数函数start=time(NULL);/start=time(NULL);/记录开始时间记录开始时间return 0;return 0;3 34 4/intintdiff_time()diff_time()/记录结束时间记录结束时间并算时间差函数并算时间差函数finish=time(NULL);/finish=time(NULL);/记录结束时间记录结束时间printf(printf(用用时时=%f=%f秒秒n,difftime(finish,start);n,difftime(finish,start);/输出结果输出结果return 0;return 0;/3 35 5void sort_p(int*d,int*b)void sort_p(int*d,int*b)/tmp2=(arg_merge_data/tmp2=(arg_merge_data(struct arg_merge_data);(struct arg_merge_data);int i;int i;intint/剩余数据初始化剩余数据初始化 merge_block=0;/merge_block=0;/归并块归并块=0=0start_time();start_time();for(i=0;iP;i+)for(i=0;iP;i+)/m_list0 /m_list0中的两个数组初始中的两个数组初始化化m_list0.begini=0;m_list0.begini=0;m_list0.counti=0;m_list0.counti=0;m_list0.merge_size=0;m_list0.merge_size=0;/m_list0/m_list0中的归并大小初始化中的归并大小初始化3 36 6*)*)calloc(merge_blockcalloc(merge_block+l,l,sizeofsizeofremain_data=N;remain_data=N;m_list0.global_pos=0;m_list0.global_pos=0;/m_list0/m_list0中的全局位置初始化中的全局位置初始化 forsortai.k=i;forsortai.k=i;forsortai.d=di;forsortai.d=di;struct struct*forsortb=&forsortai;*forsortb=&forsortai;pthreadi=CreateThread(NULL,0,pthreadi=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)sort,(LPTHREAD_START_ROUTINE)sort,forsortb,0,&(thr_idi);forsortb,0,&(thr_idi);/产生产生 p p 个线程个线程(线程(线程 idid,使用,使用sortsort 函数,参数传递函数,参数传递 didi)WaitForMultipleObjectsWaitForMultipleObjects线程结束线程结束/printf(printf(每每个个线线程程先先对对自自己己快快排排时时n);n);3 37 7for(i=0;iP;i+)for(i=0;iL*P)while(remain_dataL*P)/剩剩 余余数据大于数据大于 L*PL*Pint bound_value;int bound_value;int bucket;int bucket;bound_value=find_bound_value(d,&(bound_value=find_bound_value(d,&(m_listmerge_block),&bucket);m_listmerge_block),&bucket);find_bound(d,&(m_listmerge_blofind_bound(d,&(m_listmerge_block),bucket,bound_value);ck),bucket,bound_value);remain_data-=m_listmerge_blockremain_data-=m_listmerge_block.merge_size;.merge_size;m_listmerge_block.merged=0;m_listmerge_block.merged=0;merge_block+;merge_block+;3 38 8if(merge_block=P*P)if(merge_block=P*P)/溢出处理溢出处理printf(blockprintf(blockpartitionpartitionisisgreater than P2n);greater than P2n);break;break;printf(P