我找到了一种使用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));
}
}
}
答案 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);
}