如何使用Java大双数?

时间:2013-11-27 10:45:55

标签: java bigdecimal pi

我找到了一种使用BBS算法计算Pi数的解决方案。但我遇到了一个问题。如果使用双变量,我会错过精度。有什么建议可以解决吗?

这是我的代码:

public class Pi {
    public static void main(String[] args) {
        int n = 5;

        for (int k = 0; k < n; k++) {
            int a0 = (int) Math.pow(16, k);

            double a1 = (double) 4 / (8 * k + 1);
            double a2 = (double) 2 / (8 * k + 4);
            double a3 = (double) 1 / (8 * k + 5);
            double a4 = (double) 1 / (8 * k + 6);

            double a5 = a1 - a2 - a3 - a4;
            double a6 = (double) 1 / a0;
            double elem = a5 * a6;

            System.out.println(new BigDecimal(elem));
        }
    }
}

2 个答案:

答案 0 :(得分:4)

问题是你在计算过程中使用双打,因此不可避免地会失去准确性。是的,你最后使用的是BigDecimal,但只有在已经通过将数据置于双精度数据之后才会使用它。

解决方案是在计算中的任何一点不使用双精度。使用BigDecimal进行每一步。

使用一个比喻:你正在做的是试图将游泳池的水倒入玻璃杯中,然后将玻璃杯倒入游泳池并期待它被填满。不,它不会,因为大部分水不适合玻璃,只是倾倒在地上。

答案 1 :(得分:2)

如果您需要BigDecimal的精度,则需要将其用于所有计算。仅在结尾处将结果从double转换为BigDecimal是不够的,因为那时精度已经消失。

您需要将所有aX变量转换为BigDecimal,并使用对BigDecimal类的相应方法的调用替换运算符:

BigDecimal pi = BigDecimal.ZERO;
for (int k = 0; k < n; k++) {
    BigDecimal a0 = new BigDecimal(16).pow(k);
    BigDecimal a1 = new BigDecimal(4).divide(new BigDecimal(8*k+1), 20, RoundingMode.HALF_UP);
    BigDecimal a2 = new BigDecimal(2).divide(new BigDecimal(8*k+4), 20, RoundingMode.HALF_UP);
    BigDecimal a3 = new BigDecimal(1).divide(new BigDecimal(8*k+5), 20, RoundingMode.HALF_UP);
    BigDecimal a4 = new BigDecimal(1).divide(new BigDecimal(8*k+6), 20, RoundingMode.HALF_UP);
    BigDecimal a5 = a1.subtract(a2).subtract(a3).subtract(a4);
    BigDecimal a6 = BigDecimal.ONE.divide(a0, 20, RoundingMode.HALF_UP);
    pi.add(a5.multiply(a6));
    System.out.println(pi);
}

Demo on ideone