Commit 360ebb7e authored by Stefan Behnel's avatar Stefan Behnel

use same code as in Overflow.c for optimised int division/modulus

parent 9c10cc5c
...@@ -539,13 +539,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -539,13 +539,9 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
return PyInt_FromLong(x); return PyInt_FromLong(x);
return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
{{elif c_op == '%'}} {{elif c_op == '%'}}
// modulus with differing signs isn't safely portable, emulate CPython // see ExprNodes.py :: mod_int_utility_code
if (unlikely(a < 0)) {
x = (-a) % b;
if (x) x = b - x;
} else {
x = a % b; x = a % b;
} x += ((x != 0) & ((x ^ b) < 0)) * b;
return PyInt_FromLong(x); return PyInt_FromLong(x);
{{elif op == 'TrueDivide'}} {{elif op == 'TrueDivide'}}
if (8 * sizeof(long) <= 53 || likely({{ival}} <= (1L << 53) && {{ival}} >= (-(1L << 53)))) { if (8 * sizeof(long) <= 53 || likely({{ival}} <= (1L << 53) && {{ival}} >= (-(1L << 53)))) {
...@@ -554,21 +550,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -554,21 +550,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
// let Python do the rounding // let Python do the rounding
return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2); return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
{{elif op == 'FloorDivide'}} {{elif op == 'FloorDivide'}}
if ((a^b) >= 0) {
{{if order == 'ObjC'}}
// INT_MIN / -1 is the only case that overflows // INT_MIN / -1 is the only case that overflows
if (unlikely(b == -1 && ((unsigned long)a) == 0-(unsigned long)a)) if (unlikely(b == -1 && ((unsigned long)a) == 0-(unsigned long)a))
return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2); return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
{{endif}} else {
x = a / b; long q, r;
} else { // see ExprNodes.py :: div_int_utility_code
// use manual rounding when result is negative (signs differ) q = a / b;
long la = labs(a), lb = labs(b); r = a - q*b;
x = la / lb; q -= ((r != 0) & ((r ^ b) < 0));
if (x * lb != la) x = q;
x = -x - 1;
else
x = -x;
} }
return PyInt_FromLong(x); return PyInt_FromLong(x);
{{else}} {{else}}
...@@ -587,18 +578,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -587,18 +578,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
// handle most common case first to avoid indirect branch and optimise branch prediction // handle most common case first to avoid indirect branch and optimise branch prediction
if (likely(__Pyx_sst_abs(size) <= 1)) { if (likely(__Pyx_sst_abs(size) <= 1)) {
{{ival}} = likely(size) ? digits[0] : 0; {{ival}} = likely(size) ? digits[0] : 0;
{{if c_op != '%'}}if (size == -1) {{ival}} = -{{ival}};{{endif}} if (size == -1) {{ival}} = -{{ival}};
} else { } else {
switch (size) { switch (size) {
{{for _size in (2, 3, 4)}} {{for _size in (2, 3, 4)}}
{{for _case in (-_size, _size)}} {{for _case in (-_size, _size)}}
case {{_case}}: {{if c_op != '%' or _case > 0}} case {{_case}}:
if (8 * sizeof(long) - 1 > {{_size}} * PyLong_SHIFT{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) { if (8 * sizeof(long) - 1 > {{_size}} * PyLong_SHIFT{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) {
{{ival}} = {{'-' if _case < 0 else ''}}(long) {{pylong_join(_size, 'digits')}}; {{ival}} = {{'-' if _case < 0 else ''}}(long) {{pylong_join(_size, 'digits')}};
break; break;
} }
{{endif}}
// in negative case, fall through to positive calculation for '%'
// if size doesn't fit into a long anymore, fall through to default // if size doesn't fit into a long anymore, fall through to default
{{endfor}} {{endfor}}
{{endfor}} {{endfor}}
...@@ -624,26 +613,22 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -624,26 +613,22 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
} }
{{else}} {{else}}
{{if c_op == '%'}} {{if c_op == '%'}}
// see ExprNodes.py :: mod_int_utility_code
x = a % b; x = a % b;
if (unlikely(size < 0) && x) { x += ((x != 0) & ((x ^ b) < 0)) * b;
x = b - x;
}
{{elif op == 'TrueDivide'}} {{elif op == 'TrueDivide'}}
if (8 * sizeof(long) <= 53 || (size >= -52 / PyLong_SHIFT && size <= 52 / PyLong_SHIFT) || likely({{ival}} <= (1L << 53) && {{ival}} >= (-(1L << 53)))) { if (8 * sizeof(long) <= 53 || (size >= -52 / PyLong_SHIFT && size <= 52 / PyLong_SHIFT) || likely({{ival}} <= (1L << 53) && {{ival}} >= (-(1L << 53)))) {
return PyFloat_FromDouble((double)a / (double)b); return PyFloat_FromDouble((double)a / (double)b);
} }
return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
{{elif op == 'FloorDivide'}} {{elif op == 'FloorDivide'}}
if ((a^b) >= 0) { {
x = a / b; long q, r;
} else { // see ExprNodes.py :: div_int_utility_code
// use manual rounding when result is negative (signs differ) q = a / b;
long {{'la = %s(a), lb = %s(b)' % (('', 'labs') if order == 'ObjC' else ('labs', ''))}}; r = a - q*b;
x = la / lb; q -= ((r != 0) & ((r ^ b) < 0));
if (x * lb != la) x = q;
x = -x - 1;
else
x = -x;
} }
{{else}} {{else}}
x = a {{c_op}} b; x = a {{c_op}} 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