Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython float division PyExc_ZeroDivisionError checking

Tags:

python

cython

I'm doing some loop-intensive calculations and converted the code into Cython. I did profiling with cython -a option, and inspected the .html file, and it seems whenever I do the float division, there is somewhat yellow line and it does something like the following:

if (unlikely(__pyx_t_37 == 0)) {
        PyErr_Format(PyExc_ZeroDivisionError, "float division");
        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
      }

I guess it is for the cases where the divider is 0. I am using a constant for that and there is no probability that the divider is 0, and I was wondering if there is anything I can do to make it faster.

like image 664
joon Avatar asked Jan 17 '11 01:01

joon


2 Answers

You need to add @cython.cdivision(True) to avoid the exception checking.

import cython

cdef double pydivision():
  cdef int i
  cdef double k, j
  k = 2.0
  j = 0.0
  for i in range(10):
    j += i/k
  # Generated code: Python exception checking
  # /* "checksum.pyx":9
  # *   j = 0.0
  # *   for i in range(10):
  # *     j += i/k             # <<<<<<<<<<<<<<
  # *   return j
  # *
  # */
  #    if (unlikely(__pyx_v_k == 0)) {
  #      PyErr_Format(PyExc_ZeroDivisionError, "float division");
  #      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  #    }
  #    __pyx_v_j = (__pyx_v_j + (__pyx_v_i / __pyx_v_k));
  #  }
  return j

#This decorator works wonders
@cython.cdivision(True)
cdef double cdivision():
  cdef int i
  cdef double k, j
  k = 2.0
  j = 0.0
  for i in range(10):
    j += i/k
  # Generated code: no exception checking
  # /* "checksum.pyx":20
  # *   j = 0.0
  # *   for i in range(10):
  # *     j += i/k             # <<<<<<<<<<<<<<
  # *   return j
  # *
  # */
  #    __pyx_v_j = (__pyx_v_j + (__pyx_v_i / __pyx_v_k));
  #  }
  return j
like image 194
TryPyPy Avatar answered Nov 11 '22 06:11

TryPyPy


If the divisor is constant, you can multiply by 1/divisor instead

like image 41
John La Rooy Avatar answered Nov 11 '22 06:11

John La Rooy