In [1]:
%load_ext Cython

In [3]:
# pure Python
def py_int(a, b, f, N=2000):
    dx = (b-a)/N
    s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

from math import pi, sin

def sin2(x):
    return sin(x) ** 2

def py_main():
    a, b = 0.0, 2.0 * pi
    return py_int(a, b, sin2, N=400000)

In [15]:
import cProfile
cProfile.run('py_main()', sort='time')


         800005 function calls in 0.248 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.115    0.115    0.248    0.248 <ipython-input-3-59c9d8c339e5>:2(py_int)
   400000    0.101    0.000    0.133    0.000 <ipython-input-3-59c9d8c339e5>:11(sin2)
   400000    0.032    0.000    0.032    0.000 {built-in method math.sin}
        1    0.000    0.000    0.248    0.248 {built-in method builtins.exec}
        1    0.000    0.000    0.248    0.248 <ipython-input-3-59c9d8c339e5>:14(py_main)
        1    0.000    0.000    0.248    0.248 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [13]:
%%cython
def c0_int(a, b, f, N=2000):
    dx = (b-a)/N
    s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

In [6]:
def c0_main():
    a, b = 0.0, 2.0 * pi
    return c0_int(a, b, sin2, N=400000)

In [14]:
cProfile.run('c0_main()', sort='time')


         800005 function calls in 0.237 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   400000    0.103    0.000    0.135    0.000 <ipython-input-3-59c9d8c339e5>:11(sin2)
        1    0.102    0.102    0.237    0.237 {_cython_magic_615cd26453945831441324338d7ee331.c0_int}
   400000    0.032    0.000    0.032    0.000 {built-in method math.sin}
        1    0.000    0.000    0.237    0.237 {built-in method builtins.exec}
        1    0.000    0.000    0.237    0.237 <ipython-input-6-687f24b61ae9>:1(c0_main)
        1    0.000    0.000    0.237    0.237 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [16]:
%%cython
def c1_int(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

In [17]:
def c1_main():
    a, b = 0.0, 2.0 * pi
    return c1_int(a, b, sin2, N=400000)

In [19]:
cProfile.run('c1_main()', sort='time')


         800005 function calls in 0.195 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   400000    0.104    0.000    0.135    0.000 <ipython-input-3-59c9d8c339e5>:11(sin2)
        1    0.060    0.060    0.195    0.195 {_cython_magic_0687012b351a354228e70df43a396512.c1_int}
   400000    0.031    0.000    0.031    0.000 {built-in method math.sin}
        1    0.000    0.000    0.195    0.195 {built-in method builtins.exec}
        1    0.000    0.000    0.195    0.195 <ipython-input-17-a6ebf2ebba55>:1(c1_main)
        1    0.000    0.000    0.195    0.195 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [24]:
%%cython
# cython: profile=True
from math import sin

def c2_sin2(x):
    return sin(x) ** 2

def c2_int(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

In [25]:
def c2_main():
    a, b = 0.0, 2.0 * pi
    return c2_int(a, b, c2_sin2, N=400000)

In [26]:
cProfile.run('c2_main()', sort='time')


         400006 function calls in 0.134 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   400000    0.072    0.000    0.072    0.000 _cython_magic_b259557a627058b44f52a731e631b538.pyx:4(c2_sin2)
        1    0.061    0.061    0.133    0.133 _cython_magic_b259557a627058b44f52a731e631b538.pyx:7(c2_int)
        1    0.000    0.000    0.133    0.133 <ipython-input-25-55dda91e4b96>:1(c2_main)
        1    0.000    0.000    0.134    0.134 {built-in method builtins.exec}
        1    0.000    0.000    0.133    0.133 {_cython_magic_b259557a627058b44f52a731e631b538.c2_int}
        1    0.000    0.000    0.133    0.133 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [30]:
%%cython
# cython: profile=False
from libc.math cimport sin

def c3_sin2(x):
    return sin(x) ** 2

def c3_int(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

In [62]:
def c3_main():
    a, b = 0.0, 2.0 * pi
    print(c3_int(a, b, c3_sin2, N=400000))

In [63]:
cProfile.run('c3_main()', sort='time')


3.141592653589773
         37 function calls in 0.023 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.023    0.023    0.023    0.023 {_cython_magic_9c5e33031658a90e5b397b3974e4d16d.c3_int}
        1    0.000    0.000    0.023    0.023 <ipython-input-62-78bfc2be173d>:1(c3_main)
        3    0.000    0.000    0.000    0.000 iostream.py:180(schedule)
        1    0.000    0.000    0.023    0.023 {built-in method builtins.exec}
        2    0.000    0.000    0.000    0.000 iostream.py:342(write)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        3    0.000    0.000    0.000    0.000 {built-in method posix.urandom}
        2    0.000    0.000    0.000    0.000 iostream.py:284(_is_master_process)
        3    0.000    0.000    0.000    0.000 threading.py:1102(is_alive)
        3    0.000    0.000    0.000    0.000 threading.py:1060(_wait_for_tstate_lock)
        3    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.lock' objects}
        2    0.000    0.000    0.000    0.000 iostream.py:297(_schedule_flush)
        3    0.000    0.000    0.000    0.000 iostream.py:87(_event_pipe)
        2    0.000    0.000    0.000    0.000 {built-in method posix.getpid}
        1    0.000    0.000    0.023    0.023 <string>:1(<module>)
        3    0.000    0.000    0.000    0.000 threading.py:504(is_set)
        2    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [73]:
%%cython -a
from libc.math cimport sin, pi
#cimport cython

cdef inline double c4_sin2(double x):
    return sin(x) ** 2

#@cython.cdivision(True)
cdef double c4_int(double a, double b, double (*f)(double), int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

cpdef double c4_main():
    cdef double a=0.0, b=2.0*pi
    print(c4_int(a, b, c4_sin2, N=400000))


Out[73]:
Cython: _cython_magic_c931752a75e94374ce45da5b639fdc1e.pyx

Generated by Cython 0.25.2

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01: from libc.math cimport sin, pi
 02: #cimport cython
 03: 
+04: cdef inline double c4_sin2(double x):
static CYTHON_INLINE double __pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_sin2(double __pyx_v_x) {
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("c4_sin2", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+05:     return sin(x) ** 2
  __pyx_r = pow(sin(__pyx_v_x), 2.0);
  goto __pyx_L0;
 06: 
 07: #@cython.cdivision(True)
+08: cdef double c4_int(double a, double b, double (*f)(double), int N=2000):
static double __pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_int(double __pyx_v_a, double __pyx_v_b, double (*__pyx_v_f)(double), struct __pyx_opt_args_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_int *__pyx_optional_args) {
  int __pyx_v_N = ((int)0x7D0);
  int __pyx_v_i;
  double __pyx_v_dx;
  double __pyx_v_s;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("c4_int", 0);
  if (__pyx_optional_args) {
    if (__pyx_optional_args->__pyx_n > 0) {
      __pyx_v_N = __pyx_optional_args->N;
    }
  }
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_WriteUnraisable("_cython_magic_c931752a75e94374ce45da5b639fdc1e.c4_int", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 09:     cdef:
 10:         int i
+11:         double dx = (b-a)/N
  __pyx_t_1 = (__pyx_v_b - __pyx_v_a);
  if (unlikely(__pyx_v_N == 0)) {
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    __PYX_ERR(0, 11, __pyx_L1_error)
  }
  __pyx_v_dx = (__pyx_t_1 / ((double)__pyx_v_N));
+12:         double s = 0.0
  __pyx_v_s = 0.0;
+13:     for i in range(N):
  __pyx_t_2 = __pyx_v_N;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_i = __pyx_t_3;
+14:         s += f(a+i*dx)
    __pyx_v_s = (__pyx_v_s + __pyx_v_f((__pyx_v_a + (__pyx_v_i * __pyx_v_dx))));
  }
+15:     return s * dx
  __pyx_r = (__pyx_v_s * __pyx_v_dx);
  goto __pyx_L0;
 16: 
+17: cpdef double c4_main():
static PyObject *__pyx_pw_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_1c4_main(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static double __pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_main(CYTHON_UNUSED int __pyx_skip_dispatch) {
  double __pyx_v_a;
  double __pyx_v_b;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("c4_main", 0);
/* … */
  /* function exit code */
  __pyx_r = 0;
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_WriteUnraisable("_cython_magic_c931752a75e94374ce45da5b639fdc1e.c4_main", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_1c4_main(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_1c4_main(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("c4_main (wrapper)", 0);
  __pyx_r = __pyx_pf_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_main(__pyx_self);

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_main(CYTHON_UNUSED PyObject *__pyx_self) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("c4_main", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = PyFloat_FromDouble(__pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_main(0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 17, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_c931752a75e94374ce45da5b639fdc1e.c4_main", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+18:     cdef double a=0.0, b=2.0*pi
  __pyx_v_a = 0.0;
  __pyx_v_b = (2.0 * M_PI);
+19:     print(c4_int(a, b, c4_sin2, N=400000))
  __pyx_t_2.__pyx_n = 1;
  __pyx_t_2.N = 0x61A80;
  __pyx_t_1 = __pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_int(__pyx_v_a, __pyx_v_b, __pyx_f_46_cython_magic_c931752a75e94374ce45da5b639fdc1e_c4_sin2, &__pyx_t_2); 
  __pyx_t_3 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 19, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 19, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_GIVEREF(__pyx_t_3);
  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3);
  __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_print, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 19, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;

In [76]:
cProfile.run('c4_main()', sort='time')


3.141592653589773
         35 function calls in 0.008 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.008    0.008    0.008    0.008 {built-in method _cython_magic_c931752a75e94374ce45da5b639fdc1e.c4_main}
        2    0.000    0.000    0.000    0.000 iostream.py:342(write)
        3    0.000    0.000    0.000    0.000 iostream.py:180(schedule)
        1    0.000    0.000    0.008    0.008 {built-in method builtins.exec}
        3    0.000    0.000    0.000    0.000 {built-in method posix.urandom}
        2    0.000    0.000    0.000    0.000 iostream.py:284(_is_master_process)
        3    0.000    0.000    0.000    0.000 threading.py:1060(_wait_for_tstate_lock)
        3    0.000    0.000    0.000    0.000 threading.py:1102(is_alive)
        3    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.lock' objects}
        1    0.000    0.000    0.008    0.008 <string>:1(<module>)
        2    0.000    0.000    0.000    0.000 iostream.py:297(_schedule_flush)
        2    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
        3    0.000    0.000    0.000    0.000 iostream.py:87(_event_pipe)
        2    0.000    0.000    0.000    0.000 {built-in method posix.getpid}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        3    0.000    0.000    0.000    0.000 threading.py:504(is_set)



In [ ]:
# 30x faster!!!