1

我正在学习 scala 并享受它,它是一种非常强大的语言。我编写了这个程序来解决 Euler #2 问题,来自项目 euler。它是找到小于 400 万的偶数斐波那契数的总和(称为 max#)。

首先我使用了takeWhile,然后过滤:

fib().takeWhile(_ < n).filter(_ % 2 == 0).sum

然后决定在 takeWhile 之前更改顺序并使用过滤器:

fib().filter(_ % 2 == 0).takeWhile(_ < n).sum

我这样做是为了检查增加 max# 时是否存在性能差异。结果是准确的,正如预期的那样,性能几乎相同,直到我使用这个输入数字 (4000000000000001237) 并得到 2 个不同的结果。结果是:

 $ scala com.ms.E2_1 4000000000000001237

   takeWhile 1st    => 3770056902373173214
   filter 1st   => -8573983172444283806

有人可以解释为什么我在 takeWhile 之前使用过滤器时会出现此错误吗?谢谢你。

object E2_1 {

 def fib(a: Long = 0, b: Long = 1): Stream[Long] = {
  a #:: fib(b, a + b)
 }

 def main(args: Array[String]): Unit = {
   if (args.length == 1) { 
     val n = args(0).toLong     
     println("takeWhile 1st \t=> " + fib().takeWhile(_ < n).filter(_ % 2 == 0).sum)     
     println("filter 1st \t=> " + fib().filter(_ % 2 == 0).takeWhile(_ < n).sum)
  } else {
    println("missing args")
  }
 }
}
4

1 回答 1

2

溢出会根据函数的顺序对行为产生不同影响的原因是:

scala> fib().takeWhile(_ > -1).toList.reverse.take(2)
res0: List[Long] = List(7540113804746346429, 4660046610375530309)

即溢出开始之前计算的最后一个数字,大于你的目标n,是奇数

当您takeWhile第一次申请时,结果流将产生这些数字之一。该数字大于n,因此在结果溢出之前停止生产。

当您filter第一次申请时,这些奇数将被丢弃。由于溢出,产生的下一个偶数可能是负数,因此小于n,所以它将谓词传递给takeWhile! 流将继续,直到结果再次变为正数,并产生大于的数字n

于 2013-05-01T10:12:31.080 回答