【问题标题】:Why does this factorial method fail after 1676?为什么这个阶乘方法在 1676 之后会失败?
【发布时间】:2015-02-22 09:11:08
【问题描述】:

我使用 BigInteger 做了一个阶乘方法(因为 long 的限制),它是“无限的”,但是由于某种原因,当 n > 1676 时返回值不会打印(返回值是 n!)。这是我的代码:

private static BigInteger factorial (int n) {

    //init ans at 1
    BigInteger ans = BigInteger.ONE;

    //multiply ans by decreasing n
    while (n > 1) {
        ans = ans.multiply(BigInteger.valueOf(n--));
    }

    //return ans after loop
    return ans;

}

我使用迭代方法而不是递归方法,因为我不想导致Stackoverflow Exception。 这是我所知道的:factorial(1676).toString().length() is 4679,远低于 int 甚至是短溢出限制。 然而,System.out.println(factorial(1676)) 可以工作,而System.out.println(factorial(1677) 什么也不打印。 这就是我所知道的一切,如果可以,请帮助我。

【问题讨论】:

  • 无法复制。我的建议是使用调试器或添加一些打印语句来查看卡在哪里。
  • “我使用迭代方法而不是递归方法,因为我不想导致堆栈溢出”——对于 1700 个堆栈帧?如果你的 Java VM 实现不能处理这样一个微不足道的函数的 1700 个堆栈帧,那将是可悲的。
  • @NPE 确实如此。 OP 的代码至少为我工作了 300,000。
  • 也许 OP 在一些小东西上运行它。
  • 您的问题可能很简单,比如一行太长,IDE 无法打印。尝试只打印"Done" 而不是数字,或f.toString().substring(0,1000)),或者,要获得完整的数字,使用System.out.println(str.substring(i,i+1000)) 循环。

标签: java performance int biginteger


【解决方案1】:

嗯,你的算法是正确的,在我的机器下它工作正常。如果您对某些提升感兴趣,您可以使用并行处理。因为你可以把它分成子因子, 喜欢:

n=1*2*3*4....*(n-1)*n

您可以将此列表拆分为更多子列表:

n! = k*l*h

在哪里

k=1*2*....*k
l=(k+1)*(k+2)*...*h
h=(h+1)*...*n

要点是计算子模块,然后聚合它们。

这个话题不久前得到了回答: factorial function - parallel processing

【讨论】:

  • 这是 Java 8 中的单行代码:return IntStream.range(2,n+1).parallel().mapToObj(BigInteger::valueOf).reduce(BigInteger::multiply).orElse(BigInteger.ONE);。但是,计算数字不是 OP 的问题。
  • 我只是希望我可以在工作中使用 JDK8 :) Guava 不一样:)
  • Guava 确实支持此操作,在 BigIntegerMath.factorial 中进行了相当程度的优化。
  • @LouisWasserman 我认为 Bari 的意思是,在语法方面,带有 Guava 的 pre-8 Java 与没有 Guava 的 Java 8 不匹配 :) 当然,Guava with Java 8 是完全不同的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多