圆周率 π 的近似求法(四)
用落点概率来模拟面积比的方法,通用性强,但是准确率相对差.因此这里给出了一种针对性强的分布式求法,整体数学模型可以参考圆周率 π 的求法(二),这里引用其中方法就暂不赘述了.
引用上述方法.我们现在需要做的就是对计算进行分片,也就是 mapper ,一个整体的面积求解,可以用与y轴平行的线,按照x轴递增的规律来进行分割,最后reducer统计各部分,进行求和操作即可.
mapper部分代码如下
public class SolvingPiMapper extends Mapper<LongWritable, Text, Text, DoubleWritable> {
/**
* key 输入 读取文件的起始位置
* value 输入 文件中一行的内容
* context 输出 <k,v>形式
*/
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, DoubleWritable>.Context context)
throws IOException, InterruptedException {
//解析从文件中读取的数据
String[] message = value.toString().split("--");
//获取总片数
int totlePice = new Integer(message[0]);
//获取当前是第几片
int currPice = new Integer(message[1]);
//获取总分格数
int cell = new Integer(message[2]);
//声明总面积
double s = 0;
//初始化第一次运算时的上一个 y ;currPice*1.0/totlePice*cell
int lastY = cell-1;
//计算面积 通过 当前是第几片来确定 x 的起始值
for(int x =(int)Math.floor(currPice*1.0/totlePice*cell);x<(int)Math.floor((currPice+1)*1.0/totlePice*cell);x++){
for(int y = lastY;y>=0;y-- ){
double newX = (2*x+1)*1.0/(2*cell);
double newY = (2*y+1)*1.0/(2*cell);
//判断该节点是否在扇形中
if((newX*newX+newY*newY)<=1){
lastY = y ;
s += newY/cell;
break ;
}
}
}
context.write(new Text("PI"),new DoubleWritable(s));
}
}
reducer 部分代码
public class SolvingPiReducer extends Reducer<Text, DoubleWritable, Text, DoubleWritable> {
/**
* name 输入的 "PI"
* message 输入的"totle--num"
* context 输出的<k,v>
* 所有键位"PI"的输入都用这个方法进行处理
*/
@Override
protected void reduce(Text name, Iterable<DoubleWritable> message, Reducer<Text, DoubleWritable, Text, DoubleWritable>.Context context)
throws IOException, InterruptedException {
//累加求总面积
double sumS = 0;
for (DoubleWritable s : message) {
sumS += s.get();
}
//输出最后结果
context.write(name,new DoubleWritable(sumS*4));
}
}
主类
public class SolvingPiRunner {
//把业务逻辑相关的信息(哪个是 mapper,哪个是 reducer,要处理的数据在哪里,输出的结果放在哪里……)描述成一个 job 对象
//把这个描述好的 job 提交给集群去运行
public static void main(String[] args) throws Exception {
//用户自定义输入
System.out.println("请输入你想分的片数:");
Scanner sc = new Scanner(System.in);
int pice=new Integer(sc.nextLine());
System.out.println("请输入总分格数:");
String line=sc.nextLine();
//按照分片生成文件(在实际环境中需要在hdfc中创建文件)
for(int i=0;i<pice;i++){
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("D:\\hadoop\\input\\"+(i+1)+".txt")));
bw.write(pice+"--"+i+"--"+line);
bw.close();
}
//把业务逻辑相关的信息(哪个是 mapper,哪个是 reducer,要处理的数据在哪里,输出的结果放在哪里……)描述成一个 job 对象
//把这个描述好的 job 提交给集群去运行
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//知道这个job所在jar包
job.setJarByClass(SolvingPiRunner.class);
job.setMapperClass(SolvingPiMapper.class);
job.setReducerClass(SolvingPiReducer.class);
//设置我们的业务逻辑Mapper类的输出key 和 value 的数据
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(DoubleWritable.class);
//设置我们的业务逻辑Reducer 类的输出Key和value 的数据类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(DoubleWritable.class);
//指定要处理的数据所在的位置
FileInputFormat.setInputPaths(job, "D:\\hadoop\\input\\*.txt");
//指定处理完成后,结果所保存的位置
FileOutputFormat.setOutputPath(job, new Path("D:\\hadoop\\output\\result"));
//向yarn集群提交这个job
boolean res = job.waitForCompletion(true);
System.exit(res?0:1);
}
}
测试结果
输入
10 X 100000000
测试结果
PI 3.1415926335938655
用概率试验方法得到的结果
PI 3.141599752
虽然精确度提高但是方法针对性太强无法复用.