Thursday, December 23, 2010

Cython 2

I've been puzzling over the Cython docs and tutorial for quite a few hours now, trying to write a simple C function (in a .c file) and compile and call it from Cython. Like the example from before (here), except using my own function rather than a C math library call. I can't figure it out, so I posted questions on Stack Overflow and the Cython users list. While I'm taking a break I decided to play a bit with Fibonacci numbers.

The setup is simple: in cy.pyx (see below) we have two alternative implementations that compute the Nth element of the Fibonacci series. One version has Cython declarations that the variables are ints (and one for the function itself). The second version is plain Python. In a simple Python script cy.py we do

import pyximport
pyximport.install()
import cy

def f(N): cy.cyfib(N)
def g(N): cy.pyfib(N)

This translates the Python to C, builds it, and makes it accessible from within Python. We have to "wrap" the functions in Python calls in order to use timeit (at least, that's how I did it). Then we go to the command line and compare:

$ python -m timeit -s 'import cypy' 'cypy.f(1000)'
1000000 loops, best of 3: 1.37 usec per loop
$ python -m timeit -s 'import cypy' 'cypy.g(1000)'
1000 loops, best of 3: 232 usec per loop

The Cython version is quite a bit faster! Curiously cdef'ing the temp variable slows the timing down by a factor of 10. Hmm..

[UPDATE: There are issues!


>>> cy.cyfib(10)
55
>>> cy.cyfib(100)
-980107325
>>> cy.pyfib(100)
354224848179261915075L

I edit to use double instead of int:

>>> cy.cyfib(100)
3.54224848179262e+20
>>> cy.pyfib(100)
354224848179261915075L

It's rounded, but at least it's not negative!


]

import numpy

cpdef cyfib(int N):
cdef int a
cdef int b
cdef int counter
a = 1
b = 1
counter = 2
#cdef temp
while counter < N:
temp = a + b
a = b
b = temp
counter += 1
return b

def pyfib(N):
a,b = 1,1
counter = 2
while counter < N:
temp = a + b
a = b
b = temp
counter += 1
return b