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

时间:2015-12-02 22:19:33

标签: java loops bigdecimal pi

这是我的代码:

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个小数位的pi,但是当我尝试计算超过10个时,它会永远(至少我假设永远)。这仅仅是由于浮点除法还是什么?如果是这样,为什么它只是停止在10之后正常工作?此外,如果您在每次迭代打印pi时运行程序,它将变为3.39。 BigDecimal在这里有问题,或者我的代码有问题吗?任何帮助都会很酷。

P.S。 - 我只需要30个小数位。

2 个答案:

答案 0 :(得分:0)

你使用BigDecimal类的方式什么都不做。作为双倍的分界(以及分母变大的准确性)将是你的限制因素。

尝试使用BigDecimal组件使用BigDecimal操作进行所有这些操作 - 您可能也希望在分母中使用BigDecimal组件。

实际上你可以将分母变成一个长的并且只使用一个BigNum除法运算直到长时间溢出。我建议不要使用Double或其他任何分母,因为你将无法检测到精度的损失。

答案 1 :(得分:0)

当你使用表达式" new BigDecimal((double)(4 /(double)(i *(i + 1)*(i + 2))))"你使用double,而不是BigDecimal。并且使用双重函数来获得足够的规模来进行超过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位小数,你需要等待很多时间,我想