使用 BigDecimals 和 Nilakantha 系列计算 pi 不适用于超过 10 位小数

Calculating pi using BigDecimals and the Nilakantha series does not work for more than 10 decimal places

这是我的代码:

import java.math.BigDecimal;

public class Challenge6 {

    private static final String PI = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295";

    public static BigDecimal calculatePi(int decimals) {

        BigDecimal pi = new BigDecimal(3);
        boolean toggle = true;
        boolean enough = false;
        int i = 2;

        while (!enough) {
            BigDecimal num = new BigDecimal(
                    (double) (4 / (double) (i * (i + 1) * (i + 2))));
            System.out.println(i / 2);

            if (toggle) {
                pi = pi.add(num);
                toggle = false;

            } else {
                pi = pi.subtract(num);
                toggle = true;
            }
            i += 2;

            try {
                if (PI.substring(0, decimals + 2).equals(
                        ("" + pi).substring(0, decimals + 2))) {
                    enough = true;
                } else {

                }
            } catch (Exception ex) {
                continue;
            }
        }
        return pi;
    }

    public static void main(String[] args) {
        System.out.printf("Pi: %.30s", calculatePi(10));
    }
}

我知道它并不完美,但这只是为了好玩。我只是想知道为什么我的程序可以在 700 多次迭代中完美地生成小数点后 10 位的圆周率,但是当我尝试计算超过 10 位时,它会永远持续(至少我假设永远)。这仅仅是由于浮点除法还是其他原因?如果是这样,为什么它在 10 点后 停止 工作?此外,如果您 运行 程序在每次迭代时打印出 pi,它会变成类似 3.39 的值。 BigDecimal 在这里有问题,还是我的代码有问题?任何帮助都会很酷。

P.S。 - 我真的只需要小数点后 30 位。

您使用 BigDecimal class 的方式没有任何作用。双倍除法(以及分母变大时的精度)将是您的限制因素。

尝试使用 BigDecimal 组件执行所有这些操作,这些组件使用 BigDecimal 运算进行除法——您可能还想在分母中使用 BigDecimal 组件。

实际上你可以把分母变成一个long,然后只用一个BigNum除法运算直到long溢出。我建议不要使用 Double 或其他任何东西作为分母,因为您将无法检测到精度损失。

当您使用表达式 "new BigDecimal( (double) (4 / (double) (i * (i + 1) * (i + 2))))" 时,您使用的是 double,而不是 BigDecimal。并且使用 double ins't posible 有足够的规模来计算超过 10 位小数。

使用以下代码

public static BigDecimal calculatePi(int decimals) {
    BigDecimal pi = new BigDecimal(3);
    boolean toggle = true;
    boolean enough = false;
    int i = 2;

    while (!enough) {
        BigDecimal a = new BigDecimal(4); // All operation must be using only BigDecimal 
        BigDecimal b = new BigDecimal(i).multiply(new BigDecimal(i + 1)).multiply(new BigDecimal(i + 2));
        BigDecimal num = a.divide(b, 100, RoundingMode.FLOOR);
        System.out.println(i / 2);

        if (toggle) {
            pi = pi.add(num);
            toggle = false;

        } else {
            pi = pi.subtract(num);
            toggle = true;
        }
        i += 2;

        if (PI.substring(0, decimals + 2).equals(("" + pi).substring(0, decimals + 2))) {
            enough = true;
        }
    }
    return pi;
}

P.S.我检查这个代码是20位小数,但是30位小数你需要等待很多时间,我想