Martyr2项目实现——Number部分的问题求解 (1) Find Pi to Nth Digit
Martyr2项目实现——Number部分的问题求解 (1) Find Pi to Nth Digit
Find Pi to Nth Digit
问题描述:
Find PI to the Nth Digit – Enter a number and have the program generate PI up to that many decimal places. Keep a limit to how far the program will go.
翻译:
给定一个整数N,让程序生成精确到小数点后N为的圆周率\(\pi\)
要保证程序运行的时间在一定限度下
计算原理:
常用的圆周率的数值计算方法有级数法,迭代法,随机算法
级数法:使用圆周率\(\pi\)的级数表示来计算
高斯提出的用于平方倒数和公式
\[\frac{\pi^2}{6}=\frac{1}{1^2}+\frac{1}{2^2}+\frac{1}{3^2}...+\frac{1}{(n-1)^2}+\frac{1}{n^2}+...
\]莱布尼兹公式
\[\frac{\pi}{4}=\frac{1}{1}-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+...+(-1)^{n-1}\frac{1}{2n-1}+...
\]不过莱布尼兹公式的收敛速度很慢
拉马努金提出的公式
\[\frac{1}{\pi}=\frac{2\sqrt{2}}{9801}\sum_{k=0}^{+\infty}\frac{(4k)!(1103+26390k)}{k!^4(396^{4k})}
\]
使用级数法计算圆周率的收敛速度还是太慢
迭代算法:适合计算机程序实现的计算圆周率的方法
迭代算法的收敛速度要比无穷级数快很多
比较出名的算法是高斯-勒让德算法
高斯-勒让德算法:
引入四个数列 \(\{a_n\},\{b_n\},\{t_n\},\{p_n\}\)
他们的初值为:
\]
递推公式为:
\]
计算圆周率\(\pi\)近似值的方法:
\]
该算法每执行一次迭代,计算出的圆周率的正确位数就会增加一倍多。
具体的实现:
我们准备将圆周率计算到小数点后1000位(N<=1000)
开方运算
考虑到java的浮点数最高只支持64位double双精度浮点数,为了能够计算的更精确,考虑使用java的大数类·java.Math.BigDecimal
来进行计算。
注意到在使用高斯勒让德算法计算圆周率时,需要用到开平方运算,BigDecimal
并没有实现对大数对象的开方运算,我们需要自己实现。这里使用牛顿迭代法来计算大数的开平方。
具体的计算方法参考博客:java BigDecimal开平方
大数除法的精度问题
在进行大数运算时,对于大数除法BigDeciaml.divide()
,需要设定响应的计算精度和舍入方法(如何截断数值)
这里我们需要使用到java.Math.MathContext
类,这个类描述了数字运算符的某些规则
我们可以使用默认的规则(比如MathContext.DECIMAL128
)
也可以指定精度和舍入模式,定义自己的MathContext对象,构造方法为
MathContext(int setPrecision, RoundingMode setRoundingMode)
具体用法参考博客:java_math_MathContext
为了能够实现我们的计算要求(1000位的圆周率),我们设定大数除法的计算精度为1002位(有效数字,自定义舍入方法)
MathContext mc = new MathContext(1002, RoundingMode.HALF_EVEN);
对于开平方运算,我们设置它的计算精度为500位(精确到小数点后100位)
下表是我们计算的每次迭代可以到达的计算精度
对于给定的参数N(要求计算小数位数),我们通过查表来确定迭代次数,然后对得到的数值进行截断。
迭代次数 | 精度(小数点后精确到的位数) |
---|---|
0 | 0 |
1 | 2 |
2 | 7 |
3 | 18 |
4 | 40 |
5 | 83 |
6 | 170 |
7 | 344 |
8 | 693 |
9 | 1000 |
程序实现:
主程序
import java.math.BigDecimal;
import java.math.MathContext;
public class CalculatePi {
private static int[] map_array = {0,2,7,18,40,83,170,344,693,1000};
public static String getPiValue(int N){ //获取精确到小数点后N位的圆周率近似值
if(N<0||N>1000) return "error:给定参数超出范围!(默认参数范围为[1,1000])";
int index = 0;
for(int i=map_array.length-1;i>=1;i--){
if(N>map_array[i]) {
index = i+1;
break; //给定的参数N位于map_array[i,i+1]之间
}
}
String value = calculate(N,index);
return value;
}
private static String calculate(int N,int index) {
//利用高斯-勒让德迭代算法来计算圆周率的近似值,index为迭代的次数
if (index == 0) return "3";
//设置初值
BigDecimal a0 = new BigDecimal(1);
BigDecimal a1 = new BigDecimal(1);
BigDecimal b = CalculateSqrt.sqrt(new BigDecimal("0.5"));
BigDecimal t = new BigDecimal("0.25");
BigDecimal p = new BigDecimal(1);
BigDecimal pi = new BigDecimal(3);
MathContext mc = CalculateSqrt.mc;
//进行迭代
for (int i = 0; i < index; i++) {
a1 = a0.add(b);
a1 = a1.divide(new BigDecimal(2), mc);
b = b.multiply(a0);
b = CalculateSqrt.sqrt(b);
BigDecimal temp = new BigDecimal(1);
temp = a0.subtract(a1);
temp = temp.multiply(temp);
temp = temp.multiply(p);
t = t.subtract(temp);
p = p.multiply(new BigDecimal(2));
temp = a1.add(b);
temp = temp.multiply(temp);
temp = temp.divide(new BigDecimal(4), mc);
pi = temp.divide(t, mc);
a0 = a1;
}
return pi.toString().substring(0, N + 2);
}
public static void main(String[] args) {
int N = 10;
String pi = getPiValue(1001);
System.out.println(pi);
}
}
计算平方根程序:
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class CalculateSqrt {
private static int N = 1002;
public static MathContext mc = new MathContext(N, RoundingMode.HALF_EVEN);
private static String eps = "0."+repeatString("0",N/2)+"1";
public static void main(String[] args) {
BigDecimal n = new BigDecimal("2");
BigDecimal r = sqrt(n);
System.out.println(r.toString());
}
public static BigDecimal sqrt(BigDecimal num) {
if(num.compareTo(BigDecimal.ZERO) < 0) {
return BigDecimal.ZERO;
}
BigDecimal x = num.divide(new BigDecimal("2"), mc);
while(x.subtract(x = sqrtIteration(x, num)).abs().compareTo(new BigDecimal(eps)) > 0);
return x;
}
private static BigDecimal sqrtIteration(BigDecimal x, BigDecimal n) {
return x.add(n.divide(x, mc)).divide(new BigDecimal("2"), mc);
}
private static String repeatString(String str,int n){
StringBuffer sb = new StringBuffer();
for(int i=0;i<n;i++){
sb.append(str);
}
return sb.substring(0,sb.length());
}
}
Martyr2项目实现——Number部分的问题求解 (1) Find Pi to Nth Digit的更多相关文章
- Martyr2项目实现——Number部分问题求解(3) Prime Factorization
Martyr2项目实现--Number部分问题求解(3) Prime Factorization 质因子分解 问题描述: Prime Factorization – Have the user ent ...
- Android项目笔记整理(1)
第二部分 工作项目中以及平时看视频.看书或者看博客时整理的个人觉得挺有用的笔记 1.Activity界面切换: if(条件1){ setContentView(R.layout.ma ...
- ural 1748 The Most Complex Number 和 丑数
题目:http://acm.timus.ru/problem.aspx?space=1&num=1748 题意:求n范围内约数个数最多的那个数. Roughly speaking, for a ...
- [LeetCode][Python]17: Letter Combinations of a Phone Number
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 17: Letter Combinations of a Phone Numb ...
- ORACLE 中NUMBER类型默认的精度和Scale问题
在ORACLE数据库中,NUMBER(P,S)是最常见的数字类型,可以存放数据范围为10^-130~10^126(不包含此值),需要1~22字节(BYTE)不等的存储空间.P 是Precison的英文 ...
- PAT1082:Read Number in Chinese
1082. Read Number in Chinese (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...
- js中的Number方法
1.Number.toExponential(fractionDigits) 把number转换成一个指数形式的字符串.可选参数控制其小数点后的数字位数.它必须在0~20之间. 例如: documen ...
- 单词number 和 numeral 的区别
原文: http://blog.sina.com.cn/s/blog_72cd06360100vn7t.html be of 的用法,相当于表征特征或属性的形容词. 简单地说,“of + 名词”等于“ ...
- [Algorithm] 4. Ugly Number II
Description Ugly number is a number that only havefactors 2, 3 and 5. Design an algorithm to find th ...
随机推荐
- PHP对象传值 - 引用传值
对象传值本质上是引用传值,将一个对象变量($a)赋值给另个变量($b),实际上是将$a存储的对象内存引用地址赋值$b,此时两个变量指向的就是一个对象.其中一个变量发送改变,另一个也会跟着改变.和引用变 ...
- 将微服务部署到 Azure Kubernetes 服务 (AKS) 实践
本文是对 <.NET Tutorial - Deploy a microservice to Azure> 的翻译和实践.入门级踩坑实践,k8s 大佬请回避,以免耽误您宝贵的时间. 介绍 ...
- Css3新增的特性(1)
CSS3 模块 CSS3被拆分为"模块".旧规范已拆分成小块,还增加了新的. 一些最重要CSS3模块如下: 选择器 盒模型 背景和边框 文字特效 2D/3D转换 动画 多列布局 用 ...
- selenium常用api之切换:table切换、alert弹框切换、iframe框架切换
10.查看浏览器打开了多少个table和当前页面在哪个table 测试:打开了浏览器后,打开了一个新的标签页之后,显示此时有2个table,浏览器中当前页面展示的是第2个页面,但是代码打印显示的仍然是 ...
- nginx如何写日志
写日志函数为ngx_log_error_core,位于src/core/ngx_log.c:89行核心代码如下:while (log) { if (log->log_level < lev ...
- Vant IndexBar 在小程序中的简单使用
这篇文章是老王的朋友超超提供的,上午已经更新到原创微信公众号「软件老王」,链接,欢迎各位朋友关注老王的原创公号! 先看下最终效果图,主要是渲染一个A - Z 的 通讯录.同样的,如果你要做的是城市列表 ...
- spring标签之SCOPEprototype
默认情况下,从 bean工厂所取得的实例为Singleton(bean的singleton属性) Singleton: Spring容器只存在一个共享的bean实例,默认的配置. Prototype: ...
- 永久激活(idea,pycharm等推荐使用)
二.永久激活(推荐使用)激活码激活总是过期,永久激活后,一劳永逸,不需要每次都在网上搜索激活码了. 1.下载激活插件:jetbrains-agent.jar(关注公号[吾非同]回复pycharm获取) ...
- Hive使用Calcite CBO优化流程及SQL优化实战
目录 Hive SQL执行流程 Hive debug简单介绍 Hive SQL执行流程 Hive 使用Calcite优化 Hive Calcite优化流程 Hive Calcite使用细则 Hive向 ...
- 【转】Locust性能-零基础入门系列(3)-压力权重
本文将继续对Locust性能测试进行持续讲解,主要是讲解虚拟用户数分配和权重的关系.在locust file中进行多用户类的实现和操作.我们这次先上完整的代码: from locust import ...