Mod operator in CPP vs numpy
Hi all,
Thanks to @mstimberg, I figured out that the `mod` function in numpy and `fmod` in C have different semantics. As a result, the following code does not do the same thing with different codegen targets:

``` python
brian_prefs.codegen.target = 'numpy'
G  = NeuronGroup(1, 'x:1')
G.x = '-1 % 10'
run(defaultclock.dt)
print G.x
```

Indeed, in numpy `mod(x, N)` always returns an integer between 0 and N-1, even if x is negative, whereas C's `fmod` returns negative values if `x` is negative.
A way out is to make the `mod` operation in brian semantically consistent with numpy by writing `fmod(N+x, N)` instead of `fmod(x, N)`.

Note that sticking to numpy's semantics is maybe more convenient in the case where mod is evaluated for array indices, which shouldn't be negative.

diff --git a/brian2/codegen/generators/cpp_generator.py b/brian2/codegen/generators/cpp_generator.py
index cfe4e80e..f7ec267f 100644
--- a/brian2/codegen/generators/cpp_generator.py
+++ b/brian2/codegen/generators/cpp_generator.py
@@ -86,6 +86,27 @@ def c_data_type(dtype):
     )
 
 
+mod_support_code = ''
+typestrs = ['unsigned char', 'char', 'unsigned short', 'short', 'unsigned int', 'int', 'unsigned long', 'long',
+            'unsigned long long', 'long long', 'float', 'double', 'long double']
+floattypestrs = ['float', 'double', 'long double']
+for ix, xtype in enumerate(typestrs):
+    for iy, ytype in enumerate(typestrs):
+        hightype = typestrs[max(ix, iy)]
+        if xtype in floattypestrs or ytype in floattypestrs:
+            expr = 'fmod(fmod(x, y)+y, y)'
+        else:
+            expr = '((x%y)+y)%y'
+        mod_support_code += '''
+        inline {hightype} _brian_mod({xtype} ux, {ytype} uy)
+        {{
+            const {hightype} x = ({hightype})ux;
+            const {hightype} y = ({hightype})uy;
+            return {expr};
+        }}
+        '''.format(hightype=hightype, xtype=xtype, ytype=ytype, expr=expr)
+
+
 class CPPCodeGenerator(CodeGenerator):
     '''
     C++ language
@@ -110,6 +131,8 @@ class CPPCodeGenerator(CodeGenerator):
 
     class_name = 'cpp'
 
+    universal_support_code = deindent(mod_support_code)
+
     def __init__(self, *args, **kwds):
         super(CPPCodeGenerator, self).__init__(*args, **kwds)
         self.c_data_type = c_data_type
@@ -330,6 +353,9 @@ def determine_keywords(self):
             if func_namespace is not None:
                 self.variables.update(func_namespace)
 
+        support_code.append(self.universal_support_code)
+
+
         keywords = {'pointers_lines': stripped_deindented_lines('\n'.join(pointers)),
                     'support_code_lines': stripped_deindented_lines('\n'.join(support_code)),
                     'hashdefine_lines': stripped_deindented_lines('\n'.join(hash_defines)),
@@ -350,7 +376,6 @@ def determine_keywords(self):
 
 # Functions that need a name translation
 for func, func_cpp in [('arcsin', 'asin'), ('arccos', 'acos'), ('arctan', 'atan'),
-                       ('mod', 'fmod'),
                        ]:
     DEFAULT_FUNCTIONS[func].implementations.add_implementation(CPPCodeGenerator,
                                                                code=None,
diff --git a/brian2/codegen/generators/cython_generator.py b/brian2/codegen/generators/cython_generator.py
index f57a1e21..6bedaf5a 100644
--- a/brian2/codegen/generators/cython_generator.py
+++ b/brian2/codegen/generators/cython_generator.py
@@ -279,7 +279,7 @@ def determine_keywords(self):
 
 # Functions that need a name translation
 for func, func_cpp in [('arcsin', 'asin'), ('arccos', 'acos'), ('arctan', 'atan'),
-                       ('abs', 'fabs'), ('mod', 'fmod')]:
+                       ('abs', 'fabs')]:
     DEFAULT_FUNCTIONS[func].implementations.add_implementation(CythonCodeGenerator,
                                                                code=None,
                                                                name=func_cpp)
diff --git a/brian2/codegen/generators/numpy_generator.py b/brian2/codegen/generators/numpy_generator.py
index e45969fe..b89604df 100644
--- a/brian2/codegen/generators/numpy_generator.py
+++ b/brian2/codegen/generators/numpy_generator.py
@@ -277,8 +277,7 @@ def determine_keywords(self):
                         ('exp', np.exp), ('log', np.log), ('log10', np.log10),
                         ('sqrt', np.sqrt), ('arcsin', np.arcsin),
                         ('arccos', np.arccos), ('arctan', np.arctan),
-                        ('abs', np.abs), ('mod', np.fmod),
-                        ('sign', np.sign)]:
+                        ('abs', np.abs), ('sign', np.sign)]:
     DEFAULT_FUNCTIONS[func_name].implementations.add_implementation(NumpyCodeGenerator,
                                                                     code=func)
 
diff --git a/brian2/codegen/runtime/cython_rt/templates/common.pyx b/brian2/codegen/runtime/cython_rt/templates/common.pyx
index 0c5e0d34..a031331e 100644
--- a/brian2/codegen/runtime/cython_rt/templates/common.pyx
+++ b/brian2/codegen/runtime/cython_rt/templates/common.pyx
@@ -1,6 +1,6 @@
 #cython: boundscheck=False
 #cython: wraparound=False
-#cython: cdivision=True
+#cython: cdivision=False
 #cython: infer_types=True
 
 import numpy as _numpy
diff --git a/brian2/core/functions.py b/brian2/core/functions.py
index c8e7ce1b..d1515de7 100644
--- a/brian2/core/functions.py
+++ b/brian2/core/functions.py
@@ -450,9 +450,6 @@ def eval(cls, args):
     'abs': Function(np.abs,
                     sympy_func=sympy.functions.elementary.complexes.Abs,
                     arg_units=[None], return_unit=lambda u: u),
-    'mod': Function(np.mod,
-                    sympy_func=sympy_mod.Mod,
-                    arg_units=[None, None], return_unit=lambda u,v : u),
     'sign': Function(pyfunc=np.sign, sympy_func=sympy.sign,
                      arg_units=[None], return_unit=1),
     # functions that need special treatment
diff --git a/brian2/parsing/rendering.py b/brian2/parsing/rendering.py
index 21e2403c..1298bf5b 100644
--- a/brian2/parsing/rendering.py
+++ b/brian2/parsing/rendering.py
@@ -234,6 +234,9 @@ def render_BinOp(self, node):
         if node.op.__class__.__name__=='Pow':
             return 'pow(%s, %s)' % (self.render_node(node.left),
                                     self.render_node(node.right))
+        elif node.op.__class__.__name__=='Mod':
+            return '_brian_mod(%s, %s)' % (self.render_node(node.left),
+                                           self.render_node(node.right))
         else:
             return NodeRenderer.render_BinOp(self, node)
 
diff --git a/brian2/parsing/sympytools.py b/brian2/parsing/sympytools.py
index d91b4477..99d8d247 100644
--- a/brian2/parsing/sympytools.py
+++ b/brian2/parsing/sympytools.py
@@ -80,6 +80,8 @@ def _print_Function(self, expr):
         # Special workaround for the int function
         if expr.func.__name__ == 'int_':
             return "int(%s)" % self.stringify(expr.args, ", ")
+        elif expr.func.__name__ == 'Mod':
+            return '((%s)%%(%s))' % (self.doprint(expr.args[0]), self.doprint(expr.args[1]))
         else:
             return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ")
 
diff --git a/brian2/tests/test_functions.py b/brian2/tests/test_functions.py
index 79e2b078..74de8d69 100644
--- a/brian2/tests/test_functions.py
+++ b/brian2/tests/test_functions.py
@@ -69,9 +69,7 @@ def test_math_functions():
 
         # Functions/operators
         scalar = 3
-        # TODO: We are not testing the modulo operator here since it does
-        #       not work for double values in C
-        for func, operator in [(np.power, '**')]:
+        for func, operator in [(np.power, '**'), (np.mod, '%')]:
 
             # Calculate the result directly
             numpy_result = func(test_array, scalar)
diff --git a/brian2/tests/test_neurongroup.py b/brian2/tests/test_neurongroup.py
index fe1322d7..c60a58f4 100644
--- a/brian2/tests/test_neurongroup.py
+++ b/brian2/tests/test_neurongroup.py
@@ -48,6 +48,25 @@ def test_creation():
     # neither string nor Equations object as model description
     assert_raises(TypeError, lambda: NeuronGroup(1, object()))
 
+@attr('codegen-independent')
+def test_integer_variables_and_mod():
+    '''
+    Test that integer operations and variable definitions work.
+    '''
+    n = 10
+    eqs = '''
+    dv/dt = (a+b+j+k)/second : 1
+    j = i%n : integer
+    k = i/n : integer
+    a = v%(i+1) : 1
+    b = v%(2*v) : 1
+    '''
+    G = NeuronGroup(100, eqs)
+    G.v = np.random.rand(len(G))
+    run(1*ms)
+    assert_equal(G.j[:], G.i[:]%n)
+    assert_equal(G.k[:], G.i[:]/n)
+    assert_equal(G.a[:], G.v[:]%(G.i[:]+1))
 
 @attr('codegen-independent')
 def test_variables():
@@ -1169,6 +1188,7 @@ def test_random_vector_values():
 
 if __name__ == '__main__':
     test_creation()
+    test_integer_variables_and_mod()
     test_variables()
     test_scalar_variable()
     test_referred_scalar_variable()
diff --git a/brian2/tests/test_parsing.py b/brian2/tests/test_parsing.py
index 5dfdcee3..06c863ff 100644
--- a/brian2/tests/test_parsing.py
+++ b/brian2/tests/test_parsing.py
@@ -8,6 +8,7 @@
 from numpy.testing import assert_allclose, assert_raises
 import numpy as np
 
+from brian2.codegen.generators.cpp_generator import CPPCodeGenerator
 from brian2.codegen.runtime.weave_rt.weave_rt import get_compiler_and_args
 from brian2.core.preferences import prefs
 from brian2.core.variables import Constant
@@ -44,7 +45,6 @@ def __init__(self, variables, namespace=None):
         self.namespace = namespace
 
 
-# TODO: add some tests with e.g. 1.0%2.0 etc. once this is implemented in C++
 TEST_EXPRESSIONS = '''
     a+b+c*d-f+g-(b+d)-(a-c)
     a**b**2
@@ -65,6 +65,10 @@ def __init__(self, variables, namespace=None):
     a>0.5 and b>0.5 or c>0.5
     a>0.5 and b>0.5 or not c>0.5
     2%4
+    -1%4
+    2.3%5.6
+    2.3%5
+    -1.2%3.4
     17e-12
     42e17
     '''
@@ -119,6 +123,7 @@ def cpp_evaluator(expr, ns):
     compiler, extra_compile_args = get_compiler_and_args()
     with std_silent():
         return weave.inline('return_val = %s;' % expr, ns.keys(), local_dict=ns,
+                            support_code=CPPCodeGenerator.universal_support_code,
                             compiler=compiler,
                             extra_compile_args=extra_compile_args,
                             extra_link_args=prefs['codegen.cpp.extra_link_args'],
@@ -430,7 +435,7 @@ def test_sympytools():
 if __name__=='__main__':
     test_parse_expressions_python()
     test_parse_expressions_numpy()
-    #test_parse_expressions_cpp()
+    test_parse_expressions_cpp()
     test_parse_expressions_sympy()
     test_abstract_code_dependencies()
     test_is_boolean_expression()
['brian2/codegen/runtime/cython_rt/templates/common.pyx', 'brian2/parsing/sympytools.py', 'brian2/tests/test_functions.py', 'brian2/codegen/generators/numpy_generator.py', 'brian2/codegen/generators/cython_generator.py', 'brian2/core/functions.py', 'brian2/tests/test_neurongroup.py', 'brian2/parsing/rendering.py', 'brian2/tests/test_parsing.py', 'brian2/codegen/generators/cpp_generator.py']