from Cython.Utils import UtilityCode
import StringEncoding
import Naming
+import Nodes
from Nodes import Node
import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type
# '/' or '//' operator.
cdivision = None
-
+ cdivision_warnings = False
+
def generate_evaluation_code(self, code):
if not self.type.is_pyobject:
if self.cdivision is None:
self.cdivision = (code.globalstate.directives['cdivision']
or not self.type.signed
or self.type.is_float)
- if not self.cdivision:
+ if code.globalstate.directives['cdivision_warnings']:
+ self.cdivision_warnings = True
+ code.globalstate.use_utility_code(div_mod_print_warning_utility_code)
+ code.globalstate.use_utility_code(div_warn_utility_code.specialize(self.type))
+ elif 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):
- if self.cdivision:
+ if self.cdivision_warnings:
+ return "__Pyx_div_warn_%s(%s, %s, %s)" % (
+ self.type.specalization_name(),
+ self.operand1.result(),
+ self.operand2.result(),
+ int(self.cdivision))
+ elif self.cdivision:
return "(%s / %s)" % (
self.operand1.result(),
self.operand2.result())
self.operand2.result())
-class ModNode(NumBinopNode):
+class ModNode(DivNode):
# '%' operator.
- cdivision = None
-
def is_py_operation(self):
return (self.operand1.type.is_string
or self.operand2.type.is_string
if not self.type.is_pyobject:
if self.cdivision is None:
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')
+ math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT')
+ if code.globalstate.directives['cdivision_warnings']:
+ self.cdivision_warnings = True
+ if self.type.is_int:
+ code.globalstate.use_utility_code(mod_int_helper_macro)
+ code.globalstate.use_utility_code(div_mod_print_warning_utility_code)
+ code.globalstate.use_utility_code(mod_warn_utility_code.specialize(self.type, math_h_modifier=math_h_modifier))
+ elif not self.cdivision:
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.cdivision:
+ if self.cdivision_warnings:
+ return "__Pyx_mod_warn_%s(%s, %s, %s)" % (
+ self.type.specalization_name(),
+ self.operand1.result(),
+ self.operand2.result(),
+ int(self.cdivision))
+ elif self.cdivision:
if self.type.is_float:
return "fmod%s(%s, %s)" % (
self.type.math_h_modifier,
return res;
}
""")
+
+mod_warn_utility_code = UtilityCode(
+proto="""
+static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s, %(type)s, int cdivision); /* proto */
+""",
+impl="""
+static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s a, %(type)s b, int cdivision) {
+ %(type)s res = fmod%(math_h_modifier)s(a, b);
+ if (res * b < 0) {
+ __Pyx_div_mod_warning();
+ if (!cdivision) res += b;
+ }
+ return res;
+}
+""")
+
+div_warn_utility_code = UtilityCode(
+proto="""
+static INLINE %(type)s __Pyx_div_warn_%(type_name)s(%(type)s, %(type)s, int cdivision); /* proto */
+""",
+impl="""
+static INLINE %(type)s __Pyx_div_warn_%(type_name)s(%(type)s a, %(type)s b, int cdivision) {
+ %(type)s res = a / b;
+ if (res < 0) {
+ if (__Pyx_div_mod_warning()) ;
+ if (!cdivision) res -= 1;
+ }
+ return res;
+}
+""")
+
+
+div_mod_print_warning_utility_code = UtilityCode(
+proto="""
+static int __Pyx_div_mod_warning(void); /* proto */
+""",
+impl="""
+static int __Pyx_div_mod_warning(void) {
+ int r;
+ PyObject* s;
+ #if PY_MAJOR_VERSION < 3
+ s = PyString_FromString("Warning: division with oppositely signed operands, C and Python semantics differ");
+ #else
+ s = PyUnicode_FromString("Warning: division with oppositely signed operands, C and Python semantics differ");
+ #endif
+ if (s) {
+ r = __Pyx_PrintOne(s);
+ Py_DECREF(s);
+ }
+ else r = -1;
+ return r;
+}
+""",
+requires=[Nodes.printing_one_utility_code])
>>> [test_cdiv_cmod(a, b) for a, b in v]
[(1, 7), (-1, -7), (1, -7), (-1, 7)]
+
+>>> mod_int_py_warn(-17, 10)
+Warning: division with oppositely signed operands, C and Python semantics differ
+-7
+>>> div_int_py_warn(-17, 10)
+Warning: division with oppositely signed operands, C and Python semantics differ
+-1
"""
cimport cython
cdef short q = cython.cdiv(a, b)
cdef short r = cython.cmod(a, b)
return q, r
+
+@cython.cdivision(True)
+@cython.cdivision_warnings(True)
+def mod_int_py_warn(int a, int b):
+ return a % b
+
+@cython.cdivision(True)
+@cython.cdivision_warnings(True)
+def div_int_py_warn(int a, int b):
+ return a // b