A Quick First Introduction to Cython

Let's start with a first simple example:

{{{id=8| def python_sum(n): s = int(0) # Python int's are faster than Sage ints for very small numbers for i in range(1, n+1): s += i return s /// }}} {{{id=10| python_sum(10^5) /// 5000050000 }}} {{{id=9| timeit('k = python_sum(10^5)') /// 25 loops, best of 3: 11.9 ms per loop }}}

Let's rewrite this program, but in Cython (which is a Pythonish-to-C compiler).   Note that it looks identical -- the only difference so far is that we told Sage to compile the block using Cython by putting "%cython" at the beginning of the block.

{{{id=14| %cython def cython_sum(n): s = int(0) for i in range(1, n+1): s += i return s /// }}}

There are links to two files above:

  1. A file that ends in .c -- this is the C program that the above code got turned into.  It is then compiled and linked automatically into the running copy of Sage.
  2. A file that ends in .html -- this is an annotated version of the above Cython program, where you can double click on a line to see the corresponding C code.  Try clicking.

Is this code faster?

{{{id=16| cython_sum(10^5) /// 5000050000 }}} {{{id=13| timeit('cython_sum(10^5)') /// 25 loops, best of 3: 12.1 ms per loop }}}

Nope.  Because it is really doing basically the same thing as before.      An extra thing you can do with Cython (but not) with Python is declare variables to have a specific datatype.   If you understand the implications of this, the resulting code can be dramatically faster.

{{{id=1| %cython def cython_sum_typed(n): cdef long s, i s = 0 for i in range(1, n+1): s += i return s /// }}} {{{id=3| cython_sum_typed(10^5) /// 5000050000 }}} {{{id=4| timeit('cython_sum_typed(10^5)') /// 625 loops, best of 3: 69.4 µs per loop }}} {{{id=7| 11.9/.069 /// 172.463768115942 }}}

But watch out, long integers will silently overflow, and silently behave differently depending on whether you're using a 32 or 64-bit operating system. It's better to think of them as numbers modulo some power of $2$, which is fine for certain applications.

{{{id=21| %cython def longmul(long a, long b): return a*b /// }}} {{{id=23| longmul(2^10, 2^20) /// 1073741824 }}} {{{id=26| longmul(2^20, 2^50) # overflows! /// 0 }}} {{{id=24| 2^40 * 2^50 /// 1237940039285380274899124224 }}} {{{id=25| /// }}}