Stream上的scala过滤器产生错误的结果

时间:2013-05-01 04:37:23

标签: scala

我正在学习scala并享受它,它是一种非常强大的语言。我编写了这个程序来解决Eu​​ler#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")
  }
 }
}

1 个答案:

答案 0 :(得分:2)

根据函数的顺序,溢出影响行为的原因是:

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

即。溢出开始前计算的最后一个数字(大于目标n)是奇数

首先应用takeWhile时,生成的流将生成其中一个数字。该数字大于n,因此生产在结果溢出之前停止。

首先应用filter时,这些奇数会被丢弃。由于溢出,产生的下一个偶数可能是负数,因此小于n,因此它传递takeWhile中的谓词!流将继续,直到结果再次变为正数,并生成大于n的数字。