生成pi到n位数的java

生成pi到n位数的java,java,precision,bigdecimal,pi,Java,Precision,Bigdecimal,Pi,我想知道如何生成第n位数的π。我有几个基本的想法 使用Math.PI并提高精度(如果可能的话) 使用欧拉公式生成pi,但即使在这里,我也需要提高精度(我认为) 还有Srinivasa Ramanujan生成PI的公式,该公式以其快速收敛而闻名。这一公式似乎难以实施。我相信,我还必须在这里提高设计精度。 总之,无论哪种方式,我都需要根据第n个数字的大小来提高BigDecimal的精度。如何将BigDecimal的精度提高到第n位?另外,如果有更好更快的方法,你能告诉我正确的方向吗 编辑:我只想

我想知道如何生成第n位数的π。我有几个基本的想法

  • 使用
    Math.PI
    并提高精度(如果可能的话)
  • 使用欧拉公式生成pi,但即使在这里,我也需要提高精度(我认为)
  • 还有Srinivasa Ramanujan生成PI的公式,该公式以其快速收敛而闻名。这一公式似乎难以实施。我相信,我还必须在这里提高设计精度。
  • 总之,无论哪种方式,我都需要根据第n个数字的大小来提高
    BigDecimal
    的精度。如何将
    BigDecimal
    的精度提高到第n位?另外,如果有更好更快的方法,你能告诉我正确的方向吗

    编辑:我只想生成PI。我不想用于计算。这是一个关于如何使用BigDecimal实现生成PI的想法的问题。

    • Math.PI
      属于
      double
      类型。这意味着大约15位小数的精度,这就是你所有的数据;没有任何东西会神奇地使PI的其他数字出现
    • BigDecimal
      具有任意精度
      setScale()
      允许您以所需的精度创建
      BigDecimal
      对象,大多数算术方法将根据需要自动提高精度,但精度越高,所有计算速度越慢
    • 具有讽刺意味的是,实现Ramanujan公式最困难的部分将是常量因子中的sqrt(2),因为
      BigDecimal
      没有内置的sqrt(),因此您必须编写自己的

    您需要使用
    MathContext
    来提高
    BigDecimal

    e、 g

    重要的是,您在计算中使用的所有
    BigDecimal
    s都使用
    MathContext
    。 Heron的方法只需10次迭代就可以获得1000位的精度,20次迭代就可以获得100万位的精度,所以这已经足够好了。
    另外,在程序开始时只创建一次常量
    BigDecimal
    s,例如
    26390

    您可以使用此代码

    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;
    }
    }
    

    你真的需要生成π还是需要它来计算?这是一个关于计算π背后的数学问题,还是关于如何使用
    BigDecimal
    ?我只是用BigDecimal来实现π公式,我不需要π来计算,我只想生成它。但是对于平方根,好的old Heron方法收敛速度足够快,即使有一百万(或十亿)位数的精度。对于sqrt(2)部分,我可以不使用预定义的值吗?1.41421356,或者这会以某种方式改变计算吗?@user681159:好吧,只要你想让PI的值比“预定义值”更精确,你就需要更多的sqrt(2)位数。@user681159:如果你想根据特定的常数因子计算一个非常精确的结果,这不是很明显吗,你不能用这个因子的不精确近似值来做吗?对不起,我错过了。放松点。你说的Heron方法是什么意思?@user681159 Heron的方法与牛顿-拉斐逊方法在平方根的情况下是一致的,如果你熟悉后者的话。否则:它将通过
    x(n+1)=1/2*(x\n+a/x\n)
    找到更接近
    sqrt(a)
    。它收敛于所有
    a>0
    和任何起始值
    x_0>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;
    }
    }