问题: 以交互方式输入精度等级,例如.001,然后报告每个估算值必须达到指定精度范围内的数量。 PI。
我的解决方案:
当前结果不会终止。给出了PIEstimator
类驱动程序。问题出在PIEstimates
类中。我有一些具体问题:
如何在代码中计算Wallis PI和Leibniz PI?为瓦利斯计算每个算术的方法是:
pi / 4 =(2/3)(4/3)(4/5)(6/5)(6/7)( 8/7)(8/9)* ... 并为莱布尼兹:
pi / 4 =(1 - 1/3 + 1/5 - 1/7 + 1/9 ......)
到目前为止,执行此代码的当前逻辑是否正确?使用while循环检查相应的PI计算是否在限制范围内,并且内部的for循环继续运行,直到满足while要求。然后有一个计数返回循环重复的次数。
对于.001,例如,每个公式需要多少个术语才能达到3.14059 ..和3.14259之间的值......
import java.util.Scanner;
public class PiEstimator {
public static void main(String[] args) {
System.out.println("Wallis vs Leibnitz:");
System.out.println("Terms needed to estimate pi");
System.out.println("Enter precision sought");
Scanner scan = new Scanner(System.in);
double tolerance = scan.nextDouble();
PiEstimates e = new PiEstimates(tolerance);
System.out.println("Wallis: " + e.wallisEstimate());
System.out.println("Leibnitz: " + e.leibnitzEstimate());
}
}
public class PiEstimates {
double n = 0.0;
double upperLim = 0;
double lowerLim = 0;
public PiEstimates(double tolerance) {
n = tolerance;
upperLim = Math.PI+n;
lowerLim = Math.PI-n;
}
public double wallisEstimate() {
double wallisPi = 4;
int count = 0;
while(wallisPi > upperLim || wallisPi < lowerLim) {
for (int i = 3; i <= n + 2; i += 2) {
wallisPi = wallisPi * ((i - 1) / i) * ((i + 1) / i);
}
count++;
}
return count;
}
public double leibnitzEstimate() {
int b = 1;
double leibnizPi = 0;
int count = 0;
while(leibnizPi > upperLim || leibnizPi < lowerLim) {
for (int i = 1; i < 1000; i += 2) {
leibnizPi += (4/i - 4/i+2);
}
b = -b;
count++;
}
return count;
}
}
答案 0 :(得分:0)
wallisEstimate
for (int i = 3; i <= n + 2; i += 2) {
应该是count
而不是n
:
for (int i = 3; i <= count + 2; i += 2) {
......但是算法仍然是错误的。这会更好:
public double wallisEstimate() {
double wallisPi = 4;
int count = 0;
int i = 3;
while(wallisPi > upperLim || wallisPi < lowerLim) {
wallisPi = wallisPi * ((i - 1) / i) * ((i + 1) / i);
count++;
i += 2;
}
return count;
}
同样,对于莱布尼兹函数:
public double leibnitzEstimate() {
double leibnizPi = 0;
int count = 0;
int i = 1;
while(leibnizPi > upperLim || leibnizPi < lowerLim) {
leibnizPi += (4/i - 4/i+2);
count++;
i += 4;
}
return count;
}
答案 1 :(得分:0)
对于Leibnitz,我认为内循环应该只运行count
次:
for (int i = 1; i < count; i += 2) {
leibnizPi += (4/i - 4/i+2);
}
如果它每次运行1000次,你就不知道pi何时在范围内。
答案 2 :(得分:0)
如果while循环没有终止,那么他们就不会接近PI。
Wallis: pi/4 = (2/3)(4/3)(4/5)(6/5)(6/7)(8/7)(8/9)*...
while循环将重新启动i = 3
的for循环,这将继续添加相同的术语序列,而不是继续使用模式。
这里是基于术语模式的替代解决方案草案(没有双关语意)。 如你所见,除了2之外,分子重复。除数重复,但偏离分子:它们以交替的方式递增。
通过这种方式,您可以实际计算每个单独的术语,而不是它们的对。
public double wallisEstimate() {
double wallisPi = 1;
int count = 0;
double numerator = 2;
double divisor = 3;
while(wallisPi > upperLim || wallisPi < lowerLim) {
wallisPi *= numerator / divisor;
if ( count++ & 1 == 0 )
numerator+=2;
else
divisor+=2;
}
return count;
}
还有一项更改要做,那就是upperLim
和lowerLim
的初始化。该算法接近PI/2
,因此:
upperLim = (Math.PI + tolerance)/2;
lowerLim = (Math.PI - tolerance)/2;
莱布尼兹: pi/4 = (1 - 1/3 + 1/5 - 1/7 + 1/9 ...)
这里for循环也是不需要的:最多,你将一次计算2000个术语的增量。
如果您这样写,模式就会变得明显:
1/1 - 1/3 + 1/5 - 1/7 ......
每下一个任期的除数递增2。
public double leibnitzEstimate() {
double leibnizPi = 0;
int divisor = 1;
int count = 0;
while(leibnizPi > upperLim || leibnizPi < lowerLim) {
leibnizPi += 1.0 / divisor;
divisor = -( divisor + 2 );
count++;
}
return count;
}
leibnizPi
的更新也可以这样写:
leibnizPi += sign * 1.0 / divisor;
divisor += 2;
sign = -sign;
更清楚,需要多一个变量和一个指令。
此处必须更新upperLim
和lowerLim
:算法接近PI / 4(与Leibniz不同!),所以:
upperLim = (Math.PI + tolerance)/4;
lowerLim = (Math.PI - tolerance)/4;