3月14日圆周率日—使用并行计算求圆周率π

Wesley13
• 阅读 588

关于圆周率大家再熟悉不过了:
我们从课本上学习到早在一千多年前,祖冲之将圆周率计算到3.1415926到3.1415927之间…计算机诞生后,计算圆周率被用来检测计算机的硬件性能,昼夜燃烧cpu看会不会出问题…另外一些人也想看看这个无限延伸的神秘数字背后是否有规律,能发现一些宇宙的秘密…

3月14日圆周率日—使用并行计算求圆周率π

 提起圆周率,不能不提及Fabrice Bellard,他被认为是一位计算机天才,在业界有着重要的影响。1996年他编写了一个简洁但是完整的C编译器和一个Java虚拟机Harissa。Fabrice Bellard发明的TinyCC是GNU/Linux环境下最小的ANSI C语言编译器,是目前号称编译速度最快的C编译器。Fabrice Bellard杰作众多且涉及广泛,1998年编写了一个简洁的OpenGL实现TinyGL,2003年开发了Emacs克隆QEmacs,2005年还设计了一个廉价的数字电视系统。

3月14日圆周率日—使用并行计算求圆周率π

Fabrice Bellard使用一台普通的台式电脑,完成了冲击由超级计算机保持的圆周率运算记录的壮举,他使用台式机将圆周率计算到了小数点后2.7万亿位,超过了由目前排名世界第47位的T2K Open超级计算机于去年8月份创造的小数点后2.5万亿位的记录。

Bellard使用的电脑是一台基于2.93GHz Core i7处理器的电脑,这部电脑的内存容量是6GB,硬盘则使用的是五块RAID-0配置的1.5TB容量的希捷7200.11,系统运行64位Red Hat Fedora 10操作系统,文件系统则使用Linux的ext4.

这次计算出来的圆周率数据占去了1137GB的硬盘容量,Bellard花了103天的时间计算出了这样的结果。

计算圆周率的方法有很多种:
微积分割圆法求:
3月14日圆周率日—使用并行计算求圆周率π

或者利用便于计算机计算的丘德诺夫斯基公式法求:

3月14日圆周率日—使用并行计算求圆周率π

不过这些计算方法都比较复杂,难以让读者理解和使用并行计算来求,所幸数学上的泰勒级数是个好东西,它将微积分的东西改成用无限级数来表示,这样很容易进行并行计算分解:

π=4*∑(-1)^n+1/(2n-1) 或者写为: π=4*( 1-1/3+1/5-1/7+…)
也可以得到:πn =πn-1+(-1)^n+1/(2n-1),也就是可以通过迭代前面的π值去求当前π值。

我们根据上面公式先写个单机程序来求:

public class PiTest
{
    public static void main(String[] args)
    {
        double pi=0.0;
        for(double i=1.0;i<1000000001d;i++){
            pi += Math.pow(-1,i+1)/(2*i-1);
        }
        System.out.println(4*pi);
    }
}

运行以上程序,并对照pi的标准值:3.141592653589793238462643383279…
如果i<10000,得到pi = 3.141 6926635905345 (从红色部分以后不精确了)
如果i<1000000,得到pi = 3.14159 36535907742 (从红色部分以后不精确了)
如果i<1000000000,得到pi = 3.14159265 25880504(从红色部分以后不精确了)
……
可以看到,当迭代的轮数越大,求出的π值越精确。

由于是无限累加,我们可以很容易改成并行程序求解,比如i=4n,可以分成4段并行求解,再将4部分和合并起来得到最终π值。假设我们有4台计算机,并行计算设计如下: 
3月14日圆周率日—使用并行计算求圆周率π
 
我们这里通过fourinone提供的各种并行计算模式去设计,第一次使用可以参考 分布式计算上手demo指南,开发包下载地址: http://code.google.com/p/fourinone/

程序实现:
PiWorker:是一个π计算工人实现,我们可以看到它通过命令行输入一个计算π值的起始值和结束值,我们同时启动4个PiWorker实例,启动时指定不同的起始结束参数。

PiCtor:是一个π计算包工头实现,它的实现很简单,获取到线上工人后,通过doTaskBatch进行阶段计算,等待每个工人计算完成后,将各工人返回的π计算结果合并累加。

运行步骤:
1、启动ParkServerDemo(它的IP端口已经在配置文件指定)
java -cp fourinone.jar; ParkServerDemo

3月14日圆周率日—使用并行计算求圆周率π
2、运行4个PiWorker,将迭代100,000,000轮的计算拆分到4个工人并行完成,这里方便演示是在同一台机器上,现实应用中可以在多台计算机上完成。
java  -cp fourinone.jar; PiWorker localhost 2008 1 250000000
java  -cp fourinone.jar; PiWorker localhost 2009 250000000 500000000
java  -cp fourinone.jar; PiWorker localhost 2010 500000000 750000000
java  -cp fourinone.jar; PiWorker localhost 2011 750000000 100000000

3月14日圆周率日—使用并行计算求圆周率π
3、运行PiCtor
java  -cp fourinone.jar; PiCtor
3月14日圆周率日—使用并行计算求圆周率π
 
可以看到,4个工人实例在同台机器并行完成计算π值的时间为29秒,如果是运行单机程序PiTest完成的时间在45秒,精准度都是到小数点后8位“3.14159265”,但是耗时上有明显差距,如果多机多实例,效率还会进一步提升,并行计算性能提升分析可以参考“使用并行计算大幅提升递归算法效率”。

完整demo源码如下:
// ParkServerDemo

import com.fourinone.BeanContext;
public class ParkServerDemo
{
    public static void main(String[] args)
    {
        BeanContext.startPark();
    }
}

//PiWorker

import com.fourinone.MigrantWorker;
import com.fourinone.WareHouse;

public class PiWorker extends MigrantWorker
{
    public double m=0.0,n=0.0;
    
    public PiWorker(double m, double n){
        this.m = m;
        this.n = n;
    }
    
    public WareHouse doTask(WareHouse inhouse)
    {
        double pi=0.0;
        for(double i=m;i<n;i++){
            pi += Math.pow(-1,i+1)/(2*i-1);
        }
        
        System.out.println(4*pi);
        inhouse.setObj("pi",4*pi);

        return inhouse;
    }
    
    public static void main(String[] args)
    {
        PiWorker mw = new PiWorker(Double.parseDouble(args[2]),Double.parseDouble(args[3]));
        mw.waitWorking(args[0],Integer.parseInt(args[1]),"PiWorker");
    }
}

//PiCtor

import com.fourinone.Contractor;
import com.fourinone.WareHouse;
import com.fourinone.WorkerLocal;
import java.util.Date;

public class PiCtor extends Contractor
{
    public WareHouse giveTask(WareHouse inhouse)
    {
        WorkerLocal[] wks = getWaitingWorkers("PiWorker");
        System.out.println("wks.length:"+wks.length);
        
        WareHouse[] hmarr = doTaskBatch(wks, inhouse);
        
        double pi=0.0;
        for(WareHouse result:hmarr){
            pi = pi + (Double)result.getObj("pi");
        }
        
        System.out.println("pi:"+pi);
        return inhouse;
    }
    
    public static void main(String[] args)
    {
        PiCtor a = new PiCtor();
        long begin = (new Date()).getTime();
        a.giveTask(new WareHouse());
        long end = (new Date()).getTime();
        System.out.println("time:"+(end-begin)/1000+"s");
        a.exit();
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这