【问题标题】:BigDecimal division breaks down when dividing by factorials当除以阶乘时,BigDecimal 除法失效
【发布时间】:2015-07-23 05:03:17
【问题描述】:

我正在为一个涉及除以非常大的数字的组合问题编写一个蛮力解决方案。我求助于 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 一起使用吗? 这里可能是什么问题?在此先感谢您的帮助。

【问题讨论】:

  • 你能告诉我们factorial方法吗?
  • 是的,刚刚添加。谢谢@ajb
  • 旁注:BigInteger.valueOf(n) 会将intlong 转换为BigInteger。您无需先转换为 String,这会更慢 - 由于您处于三重循环中,因此额外的时间可能会增加。

标签: java biginteger bigdecimal integer-overflow


【解决方案1】:

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 即可将它们转换为BigIntegerBigInteger 没有采用整数值的构造函数,但它有 static valueOf method

【讨论】:

  • 感谢您的帮助。我认为新的threePowerN应该写成BigInteger threePowerN = BigInteger.valueOf(3).pow(n);pow方法作用于对象本身,它不接受第二个参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 2021-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
相关资源
最近更新 更多