在我的Java类中,我必须使用Bailey-Borwein-Plouffe公式计算Pi的值,精确到15位小数。在公式中,我需要计算16到n的幂(1到5 000 000的整数);
我正在使用的公式
这是我的代码来计算:
double value = 0.0;
//Calculates and increments value by using the BBP formula
for(int i = 0; i < iterations; i++) {
if(i == 0) {
value += (1 / 1) * (
(4.0 / ((8 * i) + 1)) -
(2.0 / ((8 * i) + 4)) -
(1.0 / ((8 * i) + 5)) -
(1.0 / ((8 * i) + 6)) );
} else {
value += (1.0 / (2L<<(i<<2L))) * (
(4.0 / ((8 * i) + 1)) -
(2.0 / ((8 * i) + 4)) -
(1.0 / ((8 * i) + 5)) -
(1.0 / ((8 * i) + 6)) );
}
}
问题是,我使用按位操作(左移&lt;&lt;)来优化代码,因为如果我们尽可能快地制作程序,我们会获得奖励分数。出于某种原因,无论我尝试什么,从Pi计算的结果数字太大而无法使用。我能够得到数字1到1.5324955e + 54。在那之后,数字溢出,我得到1或0.我试图得到3.14159等但我得到3.1382357295632852因为这个数据溢出。
任何人都可以帮我吗?或者根本不值得使用按位运算来计算功率?
答案 0 :(得分:2)
可表示为大于零的双倍的最小值是2 -2048 。对于每个高于(2048/4)的项,该公式将达到零为零,即512.到50,000,000是过去的49,999,488。
答案 1 :(得分:1)
你只需要15位数?你走了:
class Class {
private static final int ITERATION_COUNT = 15;
public static void main(final String... args) {
System.out.println(generatePi());
}
private static double generatePi() {
double pi = 0;
long sixteenPowK = 1;
for (int k = 0; k < ITERATION_COUNT; k++) {
pi += 1.0 / sixteenPowK * kthTerm(k);
sixteenPowK *= 16;
}
return pi;
}
private static double kthTerm(final int k) {
return 4.0 / (8.0 * k + 1)
- 2.0 / (8.0 * k + 4)
- 1.0 / (8.0 * k + 5)
- 1.0 / (8.0 * k + 6);
}
}
我很想看到微观基准
答案 2 :(得分:1)
免责声明:我远非数值方法方面的专家。
一般来说,为了解决任何问题,我避免预先优化。一旦找到解决方案,我就开始优化,只要它以某种方式需要。
在这种情况下,我已将8 * i
乘法内联到factor8
变量,我删除了循环内的if
并计算了{{1}的初始值最重要的是,我在乘法中积累了i = 0
的值。
通过这些更改,我设法仅在(1 / 16) ^ i
次迭代中计算PI的值,精确到15位小数。这是代码:
11
输出结果为:
public class Pi {
public static void main(String[] args) {
int iterations = 11;
int start = 1;
double value = 4.0 - 2.0 / 4.0 - 1.0 / 5.0 - 1.0 / 6.0;
double oneSixteenth = 1.0 / 16.0;
double oneSixteenthToN = oneSixteenth;
for (int i = start; i < iterations; i++) {
double factor8 = 8.0 * i;
value += oneSixteenthToN * (
(4.0 / (factor8 + 1)) -
(2.0 / (factor8 + 4)) -
(1.0 / (factor8 + 5)) -
(1.0 / (factor8 + 6)));
oneSixteenthToN *= oneSixteenth;
}
System.out.println("value = " + value); // our calculated value
System.out.println(" pi = " + Math.PI); // exact value
}
}
我必须承认,我不知道代码中累积错误的原因,但我几乎可以肯定它与value = 3.141592653589793
pi = 3.141592653589793
项的计算有关。
答案 3 :(得分:0)
我已经解决了我自己的问题。事实证明,我根本不需要按位操作。由于程序创建了50M迭代来计算Pi,我可以通过使用+ =和* =操作来增加预定义变量。这是我的最终代码,它在0.2秒内以50秒的迭代计算Pi。
//Computes Pi by using the BBP formula
public double computePi(int iterations) //<=50 000 000
{
final double d = 1 / 16.0;
double a = 16.0;
double b = -8;
double pi = 0.0;
for(int k = 0; k < iterations; k++)
{
a *= d;
b += 8;
pi += a * (4.0 / (b + 1)
- 2.0 / (b + 4)
- 1.0 / (b + 5)
- 1.0 / (b + 6));
}
return pi;
}
感谢您的所有投入,它帮助了我很多,并让我重新思考我解决这个问题的方法。