以下程序经过编译和测试,有时会返回结果,有时会用
填充屏幕java.lang.StackOverflowError
at scala.BigInt$.apply(BigInt.scala:47)
at scala.BigInt.equals(BigInt.scala:129)
at scala.runtime.BoxesRunTime.equals(Unknown Source)
at bigint$.factorial(fact2.scala:3)
at bigint$.factorial(fact2.scala:3)
...
该计划:
object bigint extends Application {
def factorial(n: BigInt): BigInt = if (n == 0) 1 else n * factorial(n-1)
println("4391! = "+factorial(4391))
}
我的问题:
详细说明:
Scala编译器版本2.7.5.final - 版权所有2002-2009,LAMP / EPFL Scala 代码运行器版本2.7.5.final - 版权所有2002-2009,LAMP / EPFL
java版“1.6.0_0”OpenJDK 运行时环境(构建 1.6.0_0-b11)OpenJDK客户端虚拟机(版本1.6.0_0-b11,混合模式,共享)
Ubuntu 2.6.24-24-generic
答案 0 :(得分:13)
如果递归调用是函数中的最后一个语句,则尾调用优化仅适用于Scala。这是非常有限的。 Scala的书说:
[...]尾调用优化是 仅限于以下情况: 方法或嵌套函数调用自身 直接作为其最后一次操作, 没有通过函数值 或其他一些中间人。
在你的情况下,递归调用是一个更大的表达式的一部分,并且它本身不是最后一个操作 - 这里的最后一个操作是乘法。
This article演示了如何使其发挥作用:
class Factorial {
def factorial(n: Int): Int = {
def factorialAcc(acc: Int, n: Int): Int = {
if (n <= 1) acc
else factorialAcc(n * acc, n - 1)
}
factorialAcc(1, n)
}
}
答案 1 :(得分:7)
在Scala 2.8中,当您希望使用尾调用优化时,可以使用@tailrec注释,如果编译器无法执行此操作,则会收到警告。
答案 2 :(得分:1)
如果你真的有大数字,那么有许多approximations,例如Scala中的这个使用素数分解:
class SwingFactorial(n: Int) {
def name() = "SwingFactorial"
def value(): BigInt =
{
if (n < 0)
{
throw new IllegalArgumentException(
"Factorial: n has to be >= 0, but was " + n)
}
ndiv2OddFact = BigInt(1)
ndiv4OddFact = ndiv2OddFact
return oddFactorial(n) << (n - MathFun.bitCount(n))
}
private def oddFactorial(n: Int): BigInt =
{
val oddFact =
if (n < Small.oddFactorial.length)
{
BigInt(Small.oddFactorial(n))
}
else
{
val of = oddFactorial(n / 2)
(of * of) * oddSwing(n)
}
ndiv4OddFact = ndiv2OddFact
ndiv2OddFact = oddFact
return oddFact
}
private def oddSwing(n: Int): BigInt =
{
if (n < Small.oddSwing.length)
{
return BigInt(Small.oddSwing(n))
}
val len = if ((n % 4) != 2) (n - 1) / 4 + 1 else (n - 1) / 4
val high = n - ((n + 1) & 1)
val ndiv4 = n / 4
val oddFact = if (ndiv4 < Small.oddFactorial.length)
BigInt(Small.oddFactorial(ndiv4)) else ndiv4OddFact
return product(high, len) / oddFact
}
private def product(m: Int, len: Int): BigInt =
{
if (len == 1) return BigInt(m)
if (len == 2) {val M = m.toLong; return BigInt(M * (M - 2))}
val hlen = len >>> 1
return product(m - hlen * 2, len - hlen) * product(m, hlen)
}
private var ndiv4OddFact = BigInt(1)
private var ndiv2OddFact = BigInt(1)
}
用法:
var fs = new SwingFactorial(n)
val a = fs.value()