Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Stream[Int]#foldLeft and Stream[Int]#sum give different results

Tags:

scala

This question relates to euler project sum-of-primes, and Stream.view, but there is a bit of a twist. I want to calculate the sum of all the primes below two million. I create a generator of prime numbers defined as:

lazy val primes: Stream[Int] = 2 #:: Stream.from(3).filter(i =>
  primes.takeWhile(j => j * j <= i).forall(i % _ > 0))

I wrote two tests, one using Stream[Int]#foldLeft and one using Stream[Int]#sum:

 @Test
 def testEuler010a {
   primes.view.takeWhile(_ < 2000000).foldLeft(0L)(_ + _) mustEqual 142913828922L
 }

 @Test
 def testEuler010b {
   primes.view.takeWhile(_ < 2000000).sum mustEqual 142913828922L
 }

testEuler010a gives me the right answer while testEuler010b does not with an answer of 1179908154. I would expect that Stream[Int]#foldLeft(0L)(_ + _) would be identical to Stream[Int].sum, but it is not. Even if I materialize the Stream with a toList(), I get he same discrepancy. Is it an incorrect assumption that those methods should give the same result?

I'm using Scala 2.9.1.final.

like image 505
andyczerwonka Avatar asked Jan 18 '12 02:01

andyczerwonka


1 Answers

The problem seems to be overflow. These give the same results for me:

(primes map (_.longValue) takeWhile (_ < 2000000)).sum
(primes map (_.longValue) takeWhile (_ < 2000000)).foldLeft(0L)(_ + _)

I suppose the difference between sum and foldLeft is that the result type of sum is the same as the type of the elements being summed over (as required by the Numeric trait), but foldLeft can have a different result type, which you achieve by writing 0L.

like image 69
Owen Avatar answered Nov 08 '22 13:11

Owen