除以阶乘时,BigDecimal 除法会崩溃
BigDecimal division breaks down when dividing by factorials
我正在为涉及除以非常大的数字的组合问题编写一个强力解决方案。我求助于 BigInteger 和 BigDecimal 来处理这些问题,但是当阶乘变得足够大以至于我无法确定时,我遇到了一个错误。
int n = num;
int k = num;
BigDecimal sum = new BigDecimal("0");
BigDecimal factorialN = new BigDecimal(factorial(n));
BigInteger factorialI;
BigInteger factorialJ;
BigInteger factorialM;
BigInteger denominator;
double threePowerN = pow(3, n);
for (int i = 0; i < k; i++) {
for (int j = 0; j < k; j++) {
for (int m = 0; m < k; m++) {
if (i + j + m == n) {
factorialI = factorial(i);
factorialJ = factorial(j);
factorialM = factorial(m);
denominator = factorialI.multiply(factorialJ);
denominator = denominator.multiply(factorialM);
denominator = denominator.multiply(new BigInteger(String.valueOf((int)threePowerN)));
BigDecimal lastTerm = new BigDecimal(denominator);
lastTerm = factorialN.divide(lastTerm, 100, RoundingMode.HALF_EVEN);
sum = sum.add(lastTerm);
}
}
}
}
// prints
// -0.62366051209329651, which doesn't make sense because this should
// be a percentage between 0 and 1.
System.out.println(new BigDecimal("1").subtract(sum));
这里是 factorial
方法:
public static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
while (n != 0) {
result = result.multiply(new BigInteger(n + ""));
n--;
}
return result;
}
所有其他情况,从 n = k = num = 1 到 19,都按预期工作:打印值介于 0 和 1 之间。
一旦我达到 num = 20,sum
超过 1,并且 sum - 1
变为负数,这让我认为这里存在溢出问题。但这可以与 BigIntegers/BigDecimals 一起使用吗?
这里可能是什么问题?在此先感谢您的帮助。
320 太大,无法放入 int
。所以这会失败:
denominator = denominator.multiply(new BigInteger(String.valueOf((int)threePowerN)));
转换将环绕,您实际上将乘以一个负数。
BigInteger
有一个 pow
函数。而不是:
double threePowerN = pow(3, n);
尝试
BigInteger threePowerN = BigInteger.valueOf(3).pow(n);
然后
denominator = denominator.multiply(threePowerN);
顺便说一下,您不必将整数转换为 String
即可将它们转换为 BigInteger
。 BigInteger
没有采用整数值的构造函数,但它确实有一个 static valueOf
method.
我正在为涉及除以非常大的数字的组合问题编写一个强力解决方案。我求助于 BigInteger 和 BigDecimal 来处理这些问题,但是当阶乘变得足够大以至于我无法确定时,我遇到了一个错误。
int n = num;
int k = num;
BigDecimal sum = new BigDecimal("0");
BigDecimal factorialN = new BigDecimal(factorial(n));
BigInteger factorialI;
BigInteger factorialJ;
BigInteger factorialM;
BigInteger denominator;
double threePowerN = pow(3, n);
for (int i = 0; i < k; i++) {
for (int j = 0; j < k; j++) {
for (int m = 0; m < k; m++) {
if (i + j + m == n) {
factorialI = factorial(i);
factorialJ = factorial(j);
factorialM = factorial(m);
denominator = factorialI.multiply(factorialJ);
denominator = denominator.multiply(factorialM);
denominator = denominator.multiply(new BigInteger(String.valueOf((int)threePowerN)));
BigDecimal lastTerm = new BigDecimal(denominator);
lastTerm = factorialN.divide(lastTerm, 100, RoundingMode.HALF_EVEN);
sum = sum.add(lastTerm);
}
}
}
}
// prints
// -0.62366051209329651, which doesn't make sense because this should
// be a percentage between 0 and 1.
System.out.println(new BigDecimal("1").subtract(sum));
这里是 factorial
方法:
public static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
while (n != 0) {
result = result.multiply(new BigInteger(n + ""));
n--;
}
return result;
}
所有其他情况,从 n = k = num = 1 到 19,都按预期工作:打印值介于 0 和 1 之间。
一旦我达到 num = 20,sum
超过 1,并且 sum - 1
变为负数,这让我认为这里存在溢出问题。但这可以与 BigIntegers/BigDecimals 一起使用吗?
这里可能是什么问题?在此先感谢您的帮助。
320 太大,无法放入 int
。所以这会失败:
denominator = denominator.multiply(new BigInteger(String.valueOf((int)threePowerN)));
转换将环绕,您实际上将乘以一个负数。
BigInteger
有一个 pow
函数。而不是:
double threePowerN = pow(3, n);
尝试
BigInteger threePowerN = BigInteger.valueOf(3).pow(n);
然后
denominator = denominator.multiply(threePowerN);
顺便说一下,您不必将整数转换为 String
即可将它们转换为 BigInteger
。 BigInteger
没有采用整数值的构造函数,但它确实有一个 static valueOf
method.