【发布时间】:2012-05-01 02:42:16
【问题描述】:
1我正在尝试制作一个无限制的阶乘函数(只是出于好奇。)这适用于大 n(尝试高达 100000 并且它似乎有效,尽管我无法检查输出值正确性,因为它很大!)
(BigInt(1) to n).reduceRight(_*_)
但我担心整个BigInt(1) to n 范围可能都在内存中,而我只需要reduceRight 的元素一个元素。看看 Scala 的标准库代码,它看起来像 BigInt(1) to n 实际上输出整个 Range 而不是懒惰的 Stream 但我发现 Stream.range 我可以像这样使用它(注意 n+1,流范围是独家)
Stream.range[BigInt](BigInt(1), BigInt(n+1)).reduceRight(_*_)
它适用于n=10000(由于某种原因,它需要更长的时间!这让我觉得也许正常范围实际上也是Stream?)但是对于n=100000,我得到这个堆栈溢出
java.lang.StackOverflowError
at java.math.BigInteger.add(Unknown Source)
at scala.math.BigInt.$plus(BigInt.scala:161)
at scala.math.Numeric$BigIntIsIntegral$class.plus(Numeric.scala:28)
at scala.math.Numeric$BigIntIsIntegral$.plus(Numeric.scala:40)
at scala.math.Numeric$BigIntIsIntegral$.plus(Numeric.scala:40)
at scala.math.Numeric$Ops.$plus(Numeric.scala:208)
at scala.collection.immutable.Stream$$anonfun$range$1.apply(Stream.scala:695)
at scala.collection.immutable.Stream$$anonfun$range$1.apply(Stream.scala:695)
at scala.collection.immutable.Stream$Cons.tail(Stream.scala:634)
at scala.collection.immutable.Stream$Cons.tail(Stream.scala:626)
at scala.collection.LinearSeqOptimized$class.reduceRight(LinearSeqOptimized.scala:130)
at scala.collection.immutable.Stream.reduceRight(Stream.scala:47)
at scala.collection.LinearSeqOptimized$class.reduceRight(LinearSeqOptimized.scala:131)
at scala.collection.immutable.Stream.reduceRight(Stream.scala:47)
at scala.collection.LinearSeqOptimized$class.reduceRight(LinearSeqOptimized.scala:131)
at scala.collection.immutable.Stream.reduceRight(Stream.scala:47)
...
很明显reduceRight是这样称呼自己的
reduceRight(reduceRight(first, second, op), third, op)...
因此堆栈溢出。我认为它不是尾调用优化的,因为它首先减少然后在返回值之前运行,所以它不能被优化。那我怎么能解决这个问题呢?我应该放弃函数式方法并以自定义命令式代码为目标吗?
让我感到非常奇怪的是(BigInt(1) to n).reduceRight(_*_) 不会溢出大的n,而使用流几乎相同...这里发生了什么?
【问题讨论】:
标签: scala stream range stack-overflow reduce