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
而使用流几乎相同......这里发生了什么?