Monday, July 6th, 2009...20:51

Project Euler Problem #2

Jump to Comments

Problem 2 from projecteuler requested the sum of all the even Fibonacci numbers below 4 million. I had seen references to “generators” in some of the Python howtos and after further reading, this seemed like a reasonable place to try them out.

def fibGenerator():
 fib0 = 0
 fib1 = 1
 while True:
  yield fib1
  fibNext = fib0 + fib1
  fib0 = fib1
  fib1 = fibNext

Then all I had to do was keep track of a running total of the even numbers which lead to:

def sumEvenFibs():
 fib = fibGenerator()
 sum = 0
 nextFib = fib.next()
 while nextFib < 4000000:
  if nextFib & 1 == 0:
   sum += nextFib
  nextFib = fib.next()
 return sum


iterations = 1000
t = timeit.Timer("sumEvenFibs()","from __main__ import sumEvenFibs")
print "Answer: %d. %d iterations took %.3f seconds" % (sumEvenFibs(), iterations, t.repeat(1,iterations)[0])

Answer: 4613732. 1000 iterations took 0.109 seconds

The while loop in sumEvenFibs didn't seem very Pythonic so I thought about how I could go about removing it. I could change fibGenerator to take a parameter for the maximum Fibonacci number to generate. In addition, the condition that a number be even was conceptually a filter that could easily be captured in a lambda function. I ended up with this:

def fibGenerator(maxFib):
 fib0 = 0
 fib1 = 1
 while fib1 < maxFib:
  yield fib1
  fibNext = fib0 + fib1
  fib0 = fib1
  fib1 = fibNext

def sumEvenFibs():
 fib = fibGenerator(4000000)
 return sum(filter((lambda x: x & 1 == 0),fib))

Which performed about as well, and is much cleaner. Looking through the forums it turns out there is a pattern to the Fibonacci numbers (odd, odd, even...) so it's pretty easy to get rid of the even check as well:

def evenFibGenerator(maxFib):
 fib0 = 1
 fib1 = 2
 while fib1 < maxFib:
  yield fib1
  temp = fib0 + (2 * fib1)
  fib1 = (2 * fib0) + (3 * fib1)
  fib0 = temp

def sumFibs():
 fib = evenFibGenerator()
 return sum([f for f in fib])

Not suprisingly this cuts the runtime by about 50%: Answer: 4613732. 1000 iterations took 0.043 seconds. On to the next problem...

Comments are closed.