Commit 03af367c authored by Stefan Behnel's avatar Stefan Behnel

optimise Python float modulus

parent 360ebb7e
......@@ -2852,11 +2852,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return self._optimise_num_binop('Rshift', node, function, args, is_unbound_method)
def _handle_simple_method_object___mod__(self, node, function, args, is_unbound_method):
if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode):
return node
if not args[1].has_constant_result() or not (2 <= args[1].constant_result <= 2**30):
return node
return self._optimise_num_binop('Remainder', node, function, args, is_unbound_method)
return self._optimise_num_div('Remainder', node, function, args, is_unbound_method)
def _handle_simple_method_object___floordiv__(self, node, function, args, is_unbound_method):
return self._optimise_num_div('FloorDivide', node, function, args, is_unbound_method)
......@@ -2892,6 +2888,9 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def _handle_simple_method_float___div__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Divide', node, function, args, is_unbound_method)
def _handle_simple_method_float___mod__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Remainder', node, function, args, is_unbound_method)
def _handle_simple_method_float___eq__(self, node, function, args, is_unbound_method):
return self._optimise_num_binop('Eq', node, function, args, is_unbound_method)
......@@ -2928,7 +2927,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
is_float = isinstance(numval, ExprNodes.FloatNode)
if is_float:
if operator not in ('Add', 'Subtract', 'TrueDivide', 'Divide', 'Eq', 'Ne'):
if operator not in ('Add', 'Subtract', 'Remainder', 'TrueDivide', 'Divide', 'Eq', 'Ne'):
return node
elif operator == 'Divide':
# mixed old-/new-style division is not currently optimised for integers
......
......@@ -687,7 +687,7 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
{{py: pyval, fval = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py:
c_op = {
'Add': '+', 'Subtract': '-', 'TrueDivide': '/', 'Divide': '/',
'Add': '+', 'Subtract': '-', 'TrueDivide': '/', 'Divide': '/', 'Remainder': '%',
'Eq': '==', 'Ne': '!=',
}[op]
}}
......@@ -768,7 +768,15 @@ static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, dou
{{else}}
// copied from floatobject.c in Py3.5:
PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL)
{{if c_op == '%'}}
result = fmod(a, b);
if (result)
result += ((result < 0) ^ (b < 0)) * b;
else
result = copysign(0.0, b);
{{else}}
result = a {{c_op}} b;
{{endif}}
PyFPE_END_PROTECT(result)
return PyFloat_FromDouble(result);
{{endif}}
......
......@@ -173,6 +173,25 @@ def mod_obj_m2(int2):
return int1
def mod_obj_m2f(obj2):
"""
>>> 0 % -2.0
-0.0
>>> mod_obj_m2f(0)
-0.0
>>> 1 % -2.0
-1.0
>>> mod_obj_m2f(1)
-1.0
>>> 9 % -2.0
-1.0
>>> mod_obj_m2f(9)
-1.0
"""
result = obj2 % -2.0
return result
def modint(int int2, int int3):
"""
>>> modint(9,2)
......
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