使用Java生成π到第n位的数字

9
我想知道如何生成pi的第n位。我有一些基本的想法。
  1. 使用Math.PI并增加精度(如果可能的话)
  2. 使用欧拉公式来生成pi,但即使在这里,我也需要增加精度(我认为) Euler's formula for PI
  3. 还有Srinivasa Ramanujan的公式用于生成PI,该公式以其迅速收敛而闻名。这个公式似乎很难实现。我相信,我也必须在这里增加小数精度。
    enter image description here
总之,无论哪种方式,我都需要根据第n个数字的情况增加BigDecimal的精度。我该如何增加BigDecimal的精度到第n位?另外,如果有更好和更快的方法,请指点我正确的方向。
编辑:我只想生成PI。我不想用于计算。这是一个关于如何使用BigDecimal来实现我的PI生成想法的问题。

你是否真的需要生成Pi,还是只需要用它进行计算? - Goran Jovic
这是关于计算pi的数学问题,还是关于如何使用BigDecimal - Oliver Charlesworth
我只是使用BigDecimal来实现PI公式,而不需要计算PI,我只是想生成它。 - Jeel Shah
3个回答

7
  • Math.PI的数据类型是double,这意味着它只有约15个小数位的精度,这是你所拥有的全部数据。没有什么能像魔术一样让额外的PI数字出现。
  • BigDecimal具有任意精度。使用setScale()可以创建具有所需精度的BigDecimal对象,大多数算法方法会根据需要自动增加精度,但当然,精度越高,所有计算就会越慢。
  • 实现Ramanujan公式最困难的部分恰恰是常量因子中的sqrt(2),因为BigDecimal中没有内置的sqrt()方法,所以你需要编写自己的方法。

1
但对于平方根,即使精度达到一百万(或十亿)位数字,老牌的海伦方法收敛得足够快。 - Daniel Fischer
对于sqrt(2)部分,我能否不使用预定义值1.41421356,或者那样会改变计算结果吗? - Jeel Shah
@user681159:嗯,一旦你想让你的PI值比那个“预定义值”更精确,你就需要更多位数的sqrt(2)。 - Michael Borgwardt
2
@user681159:如果你想基于一个特定的常数因子计算非常精确的结果,那么使用该因子的不精确近似是无法实现的,这不是很明显吗? - Michael Borgwardt
抱歉,我错过了。给我点时间。 - Jeel Shah
关于您最后提到的,关于2的平方根是最难的问题,您是否可以使用BigDecimal sr2 = new BigDecimal(new BigDecimal(2).pow(1/2), MathContext(1000));来解决,将1000替换为所需的精度?编辑:不用担心,第一个参数是int类型,不允许使用有理数指数。 - tylerr147

4
你需要使用 MathContext 来增加 BigDecimal 的精度。
例如:
MathContext mc = new MathContext(1000);
BigDecimal TWO = new BigDecimal(2, mc);

重要的是,在计算中使用的所有BigDecimal都要使用MathContext。 使用海伦方法,仅需10次迭代即可获得1000个数字的精度,20次迭代即可获得一百万个数字的精度,因此它肯定足够好。 此外,在程序开始时只需创建所有常量BigDecimal,例如26390


什么是海伦公式? - Jeel Shah
@user681159 Heron方法在平方根的情况下与牛顿-拉弗森方法重合,如果您熟悉后者的话。否则:它通过x_(n+1) = 1/2*(x_n + a/x_n)寻找更好的sqrt(a)近似值。它收敛于所有a > 0和任何起始值x_0 > 0。如果您从一个相当好的近似值开始,每一步中正确数字的数量会增加一倍(大约)。 - Daniel Fischer

0

你可以使用这段代码

import java.math.BigDecimal;
import java.math.RoundingMode;

public final class Pi {

private static final BigDecimal TWO = new BigDecimal("2");
private static final BigDecimal FOUR = new BigDecimal("4");
private static final BigDecimal FIVE = new BigDecimal("5");
private static final BigDecimal TWO_THIRTY_NINE = new BigDecimal("239");

private Pi() {}

public static BigDecimal pi(int numDigits) {

  int calcDigits = numDigits + 10;

  return FOUR.multiply((FOUR.multiply(arccot(FIVE, calcDigits)))
    .subtract(arccot(TWO_THIRTY_NINE, calcDigits)))
    .setScale(numDigits, RoundingMode.DOWN);
}

 private static BigDecimal arccot(BigDecimal x, int numDigits) {

BigDecimal unity = BigDecimal.ONE.setScale(numDigits,
  RoundingMode.DOWN);
BigDecimal sum = unity.divide(x, RoundingMode.DOWN);
BigDecimal xpower = new BigDecimal(sum.toString());
BigDecimal term = null;

boolean add = false;

for (BigDecimal n = new BigDecimal("3"); term == null ||
  term.compareTo(BigDecimal.ZERO) != 0; n = n.add(TWO)) {

  xpower = xpower.divide(x.pow(2), RoundingMode.DOWN);
  term = xpower.divide(n, RoundingMode.DOWN);
  sum = add ? sum.add(term) : sum.subtract(term);
  add = ! add;
}
return sum;
}
}

资源


这段代码存在问题,在某些情况下会导致无限循环。;-( - Werner Keil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接