We will implement the Eratosthenes Sieve algorithm to find all prime numbers smaller than a given number. The first version is coded in pure Python.
In [1]:
def primes1(n):
primes = [False, False] + [True] * (n - 2)
i = 2
while i < n:
# we do not deal with composite numbers
if not primes[i]:
i += 1
continue
k = i * i
# mark multiples of i as composite numbers
while k < n:
primes[k] = False
k += i
i += 1
return [i for i in xrange(2, n) if primes[i]]
Let's evaluate the performance of this first version.
In [2]:
n = 10000
In [3]:
primes1(20)
Out[3]:
In [4]:
%timeit primes1(n)
Now, we load the Cython magic extension to write Cython code right in the notebook.
In [5]:
%load_ext cythonmagic
All we do is to add %%cython
in the first line of the cell.
In [6]:
%%cython
def primes2(n):
primes = [False, False] + [True] * (n - 2)
i = 2
while i < n:
if not primes[i]:
i += 1
continue
k = i * i
while k < n:
primes[k] = False
k += i
i += 1
return [i for i in xrange(2, n) if primes[i]]
In [7]:
primes2(20)
Out[7]:
The speed up improvement is modest.
In [8]:
timeit primes2(n)
Now, we will precise the type of each local variable so that Cython can considerably optimize the code.
In [9]:
%%cython
def primes3(int n):
primes = [False, False] + [True] * (n - 2)
cdef int i = 2
cdef int k = 0
while i < n:
if not primes[i]:
i += 1
continue
k = i * i
while k < n:
primes[k] = False
k += i
i += 1
return [i for i in xrange(2, n) if primes[i]]
In [10]:
timeit primes3(n)
We achieve a 8x speed improvement just by specifying the variable types.