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