免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1309 | 回复: 0
打印 上一主题 下一主题

蒙特卡洛算法求 pi项目(3) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-15 16:09 |只看该作者 |倒序浏览

六、 并行算法改进
为了改进并行算法,得到更高的加速比,有两种途径可以尝试:减少线程状态转化次数和使用可并行的随机数产生算法。简介如下:

6.1 减少线程转态转换次数
       此方法具体为:在并行程序中使用互斥锁,当某一线程进入临界区后,一次性产生m个随机点,然后再退出临界区,开始对m个点进行计算;与此同时,若另一线程也要进入临界区,则被挂起,等待该线程退出。如此循环,直至两个线程均计算完所要求的点的个数,则计算输出 值,程序结束。
      
算法:
       1、确定产生点n的个数和缓冲区m(m)的值,声明互斥锁
2、某一线程进入临界区,上锁
3、该线程一次性生成m个数,其他线程若想进入则挂起等待
4、该线程退出临界区,解锁 ,开始对刚才生成的随机点进行计算
5、重复2-4步,直至每个线程均完成对所要求点的操作
6、统计COUNTi的值
7、计算 的值

在此算法中,每一线程因为争用rand()函数而产生的状态转化次数范围为[0, ],平均次数为 ,调整m的值,使生成m个随机点的时间与对m个随机点进行计算的时间相等时,则算法执行速度可达到最大值,即加速比最大。
示例程序参见附件Pmutex.c。


//并行算法

#include
#include
#include
#include
#include
#include


long cs=0; //循环次数
long count=0; //主线程有效次数
long count_thread=0; //thread线程有效次数
struct timeval start, finish; //定义开始结束时间
double diffsec,diffusec;
long t;//每次生成数据数量
pthread_mutex_t mutex;
long double *data_thread,*data_main;

//void *thread(void *)
void  thread(void)
{
   
    int i=0,j=0;
    double x,y;
    //long double *data_thread;
    long double data_thread[t];
    for(i=0;i
    {
    //  data_thread=new (long double)[t];
        pthread_mutex_lock (&mutex);//lock
        for(j=0;j
            data_thread[j]=(long double)rand()/(long double)RAND_MAX;
        pthread_mutex_unlock(&mutex);//unlock
        for(j=0;j
        {
            x=data_thread[j];
            y=data_thread[j+1];
            if((x*x+y*y)
                count_thread++;
        }
        //delete []data_thread;
    }
}

//主线程计算量为总数的一半
int main(void)
{
    printf("Please input the number:");
    scanf("%d",&cs);
        cs=cs*1000000;
    printf("Please input the number for generating the data once:");
    scanf("%d",&t);
    t=t*100000;
    pthread_t id;
    int ret;
    srand( (unsigned)time( NULL ) );
    pthread_mutex_init(&mutex,NULL);//声明互斥锁
    ret=pthread_create(&id,NULL,(void *)thread,NULL); //创建thread线程
    gettimeofday(&start,NULL); //记录开始时间
    int i=0,j=0;
    double x,y;
    long double data_main[t];   
    for(i=0;i
    {
    //  data_main=new (long double)[t];
        pthread_mutex_lock(&mutex);//lock
        for(j=0;j
            data_main[j]=(long double)rand()/(long double)RAND_MAX;
        pthread_mutex_unlock(&mutex);//unlock
        for(j=0;j
        {
            x=data_main[j];
            y=data_main[j+1];
            if((x*x+y*y)
                count++;
        }
        //delete []data_main;
    }
    pthread_join(id,NULL); //两线程同步
    count+=count_thread;
    gettimeofday(&finish,NULL); //记录结束时间
    //计算所耗时间
    diffsec=(double)finish.tv_sec-start.tv_sec;
    diffusec=(double)(finish.tv_usec-start.tv_usec)/(double)1000000;
    diffsec+=diffusec;
    //输出结果
    printf("Cost time=%f second \n",diffsec);
    printf("roop times=%d \n",cs);
    printf("effective times=%d \n",count);
    printf("pi= %f \n",4*(double)count/(double)cs);
    return(0);
}


6.2 使用可并行的随机数生成函数
       生成随机数最常用的方法为线性同余法,其C语言源代码如下:
       //myrand()用的种子
unsigned static Y =568731;
unsigned d=1
//生成伪随机数算法
double inline myrand()
{   
        Y=(15625*Y+22221)%d;
        return (double)Y/(double)(d-1);
}
通过改变种子的值,算法可生成不同的伪随机数列并且可以满足多个处理器同时调用。但调用所需时间略大于调用系统库函数rand()。(调用myrand()函数的串行算法,见附件Smyrand.c)
示例程序见附件Pmyrand.c

#include
#include
#include
#include
#include
#include
long cs=0; //总循环次数
long count=0; //主线程有效次数
long count_thread=0; //thread线程有效次数
struct timeval start, finish; //定义开始结束时间
double diffsec,diffusec;
long cs_thread=0,cs_main=0;

//myrand()用的种子
unsigned static Y =568731;
unsigned d=1
//生成伪随机数算法
double inline myrand()
{   
    Y=(15625*Y+22221)%d;
    return (double)Y/(double)(d-1);
}

//thread线程计算量为总数的0.4
void thread(void)
{
   
    int i=0;
    double x,y;
    for(i=0;i
    {
        
        x=myrand();
        y=myrand();
        if((x*x+y*y)
            count_thread++;
    }
}

//主线程计算量为总数的0.6
int main (void)
{
    printf("Please input the number:");
    scanf("%d",&cs);
    cs=cs*1000000;
    cs_main=cs*3/5;
    cs_thread=cs*2/5;
    pthread_t id;
    int ret;
    srand( (unsigned)time( NULL ) );
    ret=pthread_create(&id,NULL,(void *) thread,NULL); //创建thread线程
    gettimeofday(&start,NULL); //记录开始时间   
    int i=0;
    double x,y;
    for(i=0;i
    {      
        x=(long double)rand()/(long double)RAND_MAX;
        y=(long double)rand()/(long double)RAND_MAX;   
        if((x*x+y*y)
            count++;
    }
    pthread_join(id,NULL); //两线程同步
    count+=count_thread;
    gettimeofday(&finish,NULL); //记录结束时间   
    //计算时间差
    diffsec=(double)finish.tv_sec-start.tv_sec;
    diffusec=(double)(finish.tv_usec-start.tv_usec)/(double)1000000;
    diffsec+=diffusec;
    //输出结果
    printf("Cost time=%f second \n",diffsec);  
    printf("roop times=%d \n",cs);
    printf("effective times=%d \n",count);
    printf("pi= %f \n",4*(double)count/(double)cs);
    return(0);
}




本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/86537/showart_1964955.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP