Commit a60c7801 authored by Robert Bradshaw's avatar Robert Bradshaw

cdivision pragma as specified for CEP 516

parent 4f8ba2bf
...@@ -4229,14 +4229,27 @@ class MulNode(NumBinopNode): ...@@ -4229,14 +4229,27 @@ class MulNode(NumBinopNode):
return NumBinopNode.is_py_operation(self) return NumBinopNode.is_py_operation(self)
class FloorDivNode(NumBinopNode): class DivNode(NumBinopNode):
# '//' operator. # '/' 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): def calculate_result_code(self):
return "(%s %s %s)" % ( if self.cdivision:
self.operand1.result(), return "(%s / %s)" % (
"/", # c division is by default floor-div self.operand1.result(),
self.operand2.result()) self.operand2.result())
else:
return "__Pyx_div_%s(%s, %s)" % (
self.type.specalization_name(),
self.operand1.result(),
self.operand2.result())
class ModNode(NumBinopNode): class ModNode(NumBinopNode):
...@@ -4247,15 +4260,31 @@ class ModNode(NumBinopNode): ...@@ -4247,15 +4260,31 @@ class ModNode(NumBinopNode):
or self.operand2.type.is_string or self.operand2.type.is_string
or NumBinopNode.is_py_operation(self)) 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): def calculate_result_code(self):
if self.operand1.type.is_float or self.operand2.type.is_float: if self.cdivision:
return "fmod(%s, %s)" % ( if self.type.is_float:
self.operand1.result(), return "fmod%s(%s, %s)" % (
self.operand2.result()) self.type.math_h_modifier,
self.operand1.result(),
self.operand2.result())
else:
return "(%s %% %s)" % (
self.operand1.result(),
self.operand2.result())
else: else:
return "(%s %% %s)" % ( return "__Pyx_mod_%s(%s, %s)" % (
self.operand1.result(), self.type.specalization_name(),
self.operand2.result()) self.operand1.result(),
self.operand2.result())
class PowNode(NumBinopNode): class PowNode(NumBinopNode):
# '**' operator. # '**' operator.
...@@ -4852,20 +4881,20 @@ class CascadedCmpNode(Node, CmpNode): ...@@ -4852,20 +4881,20 @@ class CascadedCmpNode(Node, CmpNode):
binop_node_classes = { binop_node_classes = {
"or": BoolBinopNode, "or": BoolBinopNode,
"and": BoolBinopNode, "and": BoolBinopNode,
"|": IntBinopNode, "|": IntBinopNode,
"^": IntBinopNode, "^": IntBinopNode,
"&": IntBinopNode, "&": IntBinopNode,
"<<": IntBinopNode, "<<": IntBinopNode,
">>": IntBinopNode, ">>": IntBinopNode,
"+": AddNode, "+": AddNode,
"-": SubNode, "-": SubNode,
"*": MulNode, "*": MulNode,
"/": NumBinopNode, "/": DivNode,
"//": FloorDivNode, "//": DivNode,
"%": ModNode, "%": ModNode,
"**": PowNode "**": PowNode
} }
def binop_node(pos, operator, operand1, operand2): def binop_node(pos, operator, operand1, operand2):
...@@ -5639,3 +5668,34 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) { ...@@ -5639,3 +5668,34 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
return t; 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;
}
""")
...@@ -55,22 +55,22 @@ c_line_in_traceback = 1 ...@@ -55,22 +55,22 @@ c_line_in_traceback = 1
# Declare pragmas # Declare pragmas
option_types = {
'boundscheck' : bool,
'nonecheck' : bool,
'embedsignature' : bool,
'locals' : dict,
'auto_cpdef': bool,
}
option_defaults = { option_defaults = {
'boundscheck' : True, 'boundscheck' : True,
'nonecheck' : False, 'nonecheck' : False,
'embedsignature' : False, 'embedsignature' : False,
'locals' : {}, 'locals' : {},
'auto_cpdef': False, '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): def parse_option_value(name, value):
""" """
Parses value as an option value for the given name and returns Parses value as an option value for the given name and returns
......
...@@ -18,6 +18,11 @@ True ...@@ -18,6 +18,11 @@ True
[7.0, -7.0, -7.0, 7.0] [7.0, -7.0, -7.0, 7.0]
>>> [mod_double_c(a, b) for a, b in v] >>> [mod_double_c(a, b) for a, b in v]
[7.0, -7.0, -7.0, 7.0] [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 cimport cython
...@@ -50,3 +55,12 @@ def mod_float_c(float a, float b): ...@@ -50,3 +55,12 @@ def mod_float_c(float a, float b):
def mod_double_c(double a, double b): def mod_double_c(double a, double b):
return a % 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment