cdivision pragma as specified for CEP 516
authorRobert Bradshaw <robertwb@math.washington.edu>
Thu, 26 Mar 2009 02:10:09 +0000 (19:10 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Thu, 26 Mar 2009 02:10:09 +0000 (19:10 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Options.py
tests/run/cdivision_CEP_516.pyx

index 7599d16cad695c98b67f228c28cce085155e756c..5c998ebe0cc96c2ea2fdd50214dde90d693e7b69 100644 (file)
@@ -4229,14 +4229,27 @@ class MulNode(NumBinopNode):
             return NumBinopNode.is_py_operation(self)
 
 
-class FloorDivNode(NumBinopNode):
-    #  '//' operator.
+class DivNode(NumBinopNode):
+    #  '/' or '//' operator.
+    
+    def generate_evaluation_code(self, code):
+        self.cdivision = (code.globalstate.directives['cdivision'] 
+                            or not self.type.signed
+                            or self.type.is_float)
+        if not self.cdivision:
+            code.globalstate.use_utility_code(div_utility_code.specialize(self.type))
+        NumBinopNode.generate_evaluation_code(self, code)
     
     def calculate_result_code(self):
-        return "(%s %s %s)" % (
-            self.operand1.result(), 
-            "/",  # c division is by default floor-div 
-            self.operand2.result())
+        if self.cdivision:
+            return "(%s / %s)" % (
+                self.operand1.result(), 
+                self.operand2.result())
+        else:
+            return "__Pyx_div_%s(%s, %s)" % (
+                    self.type.specalization_name(),
+                    self.operand1.result(), 
+                    self.operand2.result())
 
 
 class ModNode(NumBinopNode):
@@ -4247,15 +4260,31 @@ class ModNode(NumBinopNode):
             or self.operand2.type.is_string
             or NumBinopNode.is_py_operation(self))
 
+    def generate_evaluation_code(self, code):
+        self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed
+        if not self.cdivision:
+            math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT')
+            if self.type.is_int:
+                code.globalstate.use_utility_code(mod_int_helper_macro)
+            code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier))
+        NumBinopNode.generate_evaluation_code(self, code)
+    
     def calculate_result_code(self):
-        if self.operand1.type.is_float or self.operand2.type.is_float:
-            return "fmod(%s, %s)" % (
-                self.operand1.result(), 
-                self.operand2.result())
+        if self.cdivision:
+            if self.type.is_float:
+                return "fmod%s(%s, %s)" % (
+                    self.type.math_h_modifier,
+                    self.operand1.result(), 
+                    self.operand2.result())
+            else:
+                return "(%s %% %s)" % (
+                    self.operand1.result(), 
+                    self.operand2.result())
         else:
-            return "(%s %% %s)" % (
-                self.operand1.result(), 
-                self.operand2.result())
+            return "__Pyx_mod_%s(%s, %s)" % (
+                    self.type.specalization_name(),
+                    self.operand1.result(), 
+                    self.operand2.result())
 
 class PowNode(NumBinopNode):
     #  '**' operator.
@@ -4852,20 +4881,20 @@ class CascadedCmpNode(Node, CmpNode):
 
 
 binop_node_classes = {
-    "or":        BoolBinopNode,
-    "and":    BoolBinopNode,
+    "or":       BoolBinopNode,
+    "and":      BoolBinopNode,
     "|":        IntBinopNode,
     "^":        IntBinopNode,
     "&":        IntBinopNode,
-    "<<":        IntBinopNode,
-    ">>":        IntBinopNode,
+    "<<":       IntBinopNode,
+    ">>":       IntBinopNode,
     "+":        AddNode,
     "-":        SubNode,
     "*":        MulNode,
-    "/":        NumBinopNode,
-    "//":        FloorDivNode,
+    "/":        DivNode,
+    "//":       DivNode,
     "%":        ModNode,
-    "**":        PowNode
+    "**":       PowNode
 }
 
 def binop_node(pos, operator, operand1, operand2):
@@ -5639,3 +5668,34 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
     return t;
 }
 """)
+
+# ------------------------------ Division ------------------------------------
+
+# This is so we can treat floating point and integer mod simultaneously. 
+mod_int_helper_macro = UtilityCode(proto="""
+#define fmod__Pyx_INT(a, b) ((a) % (b))
+""")
+
+mod_utility_code = UtilityCode(
+proto="""
+static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
+""",
+impl="""
+static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
+    %(type)s res = fmod%(math_h_modifier)s(a, b);
+    res += (res * b < 0) * b;
+    return res;
+}
+""")
+
+div_utility_code = UtilityCode(
+proto="""
+static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */
+""",
+impl="""
+static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
+    %(type)s res = a / b;
+    res -= (res < 0);
+    return res;
+}
+""")
index 84b692b0885f91b132785ca9cf38ddc81fc982da..de14a810fa590f5399a83e26240ae3626803431b 100644 (file)
@@ -55,22 +55,22 @@ c_line_in_traceback = 1
 
 
 # Declare pragmas
-option_types = {
-    'boundscheck' : bool,
-    'nonecheck' : bool,
-    'embedsignature' : bool,
-    'locals' : dict,
-    'auto_cpdef': bool,
-}
-
 option_defaults = {
     'boundscheck' : True,
     'nonecheck' : False,
     'embedsignature' : False,
     'locals' : {},
     'auto_cpdef': False,
+    'cdivision': True,  # Will be False in 0.12
 }
 
+# Override types possibilities above, if needed
+option_types = { }
+
+for key, val in option_defaults.items():
+    if key not in option_types:
+        option_types[key] = type(val)
+
 def parse_option_value(name, value):
     """
     Parses value as an option value for the given name and returns
index ecb66a222babcab2fbe5f0584aa3ca25fe7220e3..163fc2b3451ea5e6095dd7d99aacd40bc893f186 100644 (file)
@@ -18,6 +18,11 @@ True
 [7.0, -7.0, -7.0, 7.0]
 >>> [mod_double_c(a, b) for a, b in v]
 [7.0, -7.0, -7.0, 7.0]
+
+>>> [div_int_py(a, b) for a, b in v]
+[1, -2, 1, -2]
+>>> [div_int_c(a, b) for a, b in v]
+[1, -1, 1, -1]
 """
 
 cimport cython
@@ -50,3 +55,12 @@ def mod_float_c(float a, float b):
 def mod_double_c(double a, double b):
     return a % b
 
+
+@cython.cdivision(False)
+def div_int_py(int a, int b):
+    return a // b
+
+@cython.cdivision(True)
+def div_int_c(int a, int b):
+    return a // b
+