Problem 2
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
In [1]:
n = 4000000
In [2]:
def foo(n):
a = 0
b = 1
total = 0
while True:
c = a + b
a = b
b = c
# print b
if b > n:
break
if b % 2 == 0:
total += b
return total
In [3]:
%timeit foo(n)
correct_answer = foo(n)
correct_answer
Out[3]:
In [4]:
def fib(last):
a = 0
b = 1
while True:
c = a + b
a = b
b = c
if b > last:
break
yield b
def foo(n):
return sum([f for f in fib(n) if f % 2 == 0])
In [5]:
%timeit foo(n)
assert foo(n) == correct_answer
In [6]:
def even_fibonacci(last):
a = 0
b = 1
while True:
c = a + b
a = b
b = c
if b > last:
break
if b % 2 == 0:
yield b
def foo(n):
return sum([f for f in even_fibonacci(n)])
In [7]:
%timeit foo(n)
assert foo(n) == correct_answer
In [8]:
def unrolled_even_fibonacci(last):
a = 0
b = 1
while True:
c = a + b
a = b
b = c
c = a + b
a = b
b = c
if b > last:
break
yield b
c = a + b
a = b
b = c
def foo(n):
return sum([f for f in unrolled_even_fibonacci(n)])
In [9]:
%timeit foo(n)
assert foo(n) == correct_answer
In [10]:
def unrolled_even_fibonacci(last):
a = 0
b = 1
while True:
c = a + b
d = b + c
if d > last:
break
yield d
e = c + d
a = d
b = e
def foo(n):
return sum([f for f in unrolled_even_fibonacci(n)])
In [11]:
%timeit foo(n)
assert foo(n) == correct_answer
In [12]:
def unrolled_even_fibonacci(last):
'''
The body of the loop reminds me of a musical round.
I like how there are no wasted assignments.
'''
a = 0
b = 1
while True:
c = a + b # Frère Jacques, frère Jacques,
a = b + c # Dormez-vous? Dormez-vous?
if a > last:
break
yield a
b = c + a # Sonnez les matines! Sonnez les matines!
def foo(n):
return sum([f for f in unrolled_even_fibonacci(n)])
In [13]:
%timeit foo(n)
assert foo(n) == correct_answer
In [14]:
def unrolled_even_fibonacci(last):
'''
The body of the loop reminds me of a musical round.
I like how there are no wasted assignments.
'''
a = 0
b = 1
while True:
c = a + b # Frère Jacques, frère Jacques,
a = b + c # Dormez-vous? Dormez-vous?
if a > last:
break
yield a
b = c + a # Sonnez les matines! Sonnez les matines!
def foo(n):
return sum(unrolled_even_fibonacci(n))
In [15]:
%timeit foo(n)
assert foo(n) == correct_answer
In [16]:
def sum_even_fibonacci(last):
'''
The body of the loop reminds me of a musical round.
I like how there are no wasted assignments.
'''
total = 0
a = 0
b = 1
while True:
c = a + b
a = b + c
if a > last:
return total
total += a
b = c + a
def foo(n):
return sum_even_fibonacci(n)
In [17]:
%timeit foo(n)
assert foo(n) == correct_answer
In [18]:
def sum_even_fibonacci(last):
'''
The body of the loop reminds me of a musical round.
I like how there are no wasted assignments.
Aligned test with beginning of loop, hoping for small speed increase,
albeit at cost of ugly duplicated code before loop.
Loop code itself got easier to read.'''
total = 0
a = 0
b = 1
c = a + b
a = b + c
while a <= last:
total += a
b = c + a
c = a + b
a = b + c
return total
def foo(n):
return sum_even_fibonacci(n)
In [19]:
%timeit foo(n)
assert foo(n) == correct_answer