Commit fa0ca0c6 authored by Stefan Behnel's avatar Stefan Behnel

optimise Python operation (-n) % m

--HG--
extra : transplant_source : %0F%A1%10%B6%0D%82%1D%A3%1A%3A%B1%94%10%E9%D6%ADh%29Ni
parent 9d73d054
...@@ -500,7 +500,7 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -500,7 +500,7 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
if (likely(PyInt_CheckExact({{pyval}}))) { if (likely(PyInt_CheckExact({{pyval}}))) {
const long {{'a' if order == 'CObj' else 'b'}} = intval; const long {{'a' if order == 'CObj' else 'b'}} = intval;
{{if c_op in '+-'}} {{if c_op in '+-%'}}
long x; long x;
{{endif}} {{endif}}
long {{ival}} = PyInt_AS_LONG({{pyval}}); long {{ival}} = PyInt_AS_LONG({{pyval}});
...@@ -512,12 +512,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -512,12 +512,16 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
if (likely((x^a) >= 0 || (x^{{ '~' if op == 'Subtract' else '' }}b) >= 0)) if (likely((x^a) >= 0 || (x^{{ '~' if op == 'Subtract' else '' }}b) >= 0))
return PyInt_FromLong(x); return PyInt_FromLong(x);
return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2); return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2);
{{elif c_op == '%'}}
// modulus with differing signs isn't safely portable, emulate CPython
if (unlikely(a < 0)) {
x = (-a) % b;
if (x) x = b - x;
} else {
x = a % b;
}
return PyInt_FromLong(x);
{{else}} {{else}}
{{if c_op == '%'}}
// modulus with differing signs isn't safely portable
if (unlikely({{ival}} < 0))
return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2);
{{endif}}
// other operations are safe, no overflow // other operations are safe, no overflow
return PyInt_FromLong(a {{c_op}} b); return PyInt_FromLong(a {{c_op}} b);
{{endif}} {{endif}}
...@@ -527,13 +531,18 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -527,13 +531,18 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
if (likely(PyLong_CheckExact({{pyval}}))) { if (likely(PyLong_CheckExact({{pyval}}))) {
const long {{'a' if order == 'CObj' else 'b'}} = intval; const long {{'a' if order == 'CObj' else 'b'}} = intval;
long {{ival}}; long x, {{ival}};
switch (Py_SIZE({{pyval}})) { const Py_ssize_t size = Py_SIZE({{pyval}});
switch (size) {
case 0: {{ival}} = 0; break;
{{if c_op != '%'}} {{if c_op != '%'}}
case -1: {{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break; case -1: {{ival}} = -(sdigit)((PyLongObject*){{pyval}})->ob_digit[0]; break;
{{else}}
case -1:
// fall through to positive calculation for '%'
{{endif}} {{endif}}
case 0: {{ival}} = 0; break;
case 1: {{ival}} = ((PyLongObject*){{pyval}})->ob_digit[0]; break; case 1: {{ival}} = ((PyLongObject*){{pyval}})->ob_digit[0]; break;
case -2:
case 2: case 2:
if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
{{ival}} = (long) ((((unsigned long)((PyLongObject*){{pyval}})->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*){{pyval}})->ob_digit[0]); {{ival}} = (long) ((((unsigned long)((PyLongObject*){{pyval}})->ob_digit[1]) << PyLong_SHIFT) | ((PyLongObject*){{pyval}})->ob_digit[0]);
...@@ -542,7 +551,17 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO ...@@ -542,7 +551,17 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHO
// fall through if two platform digits don't fit into a long // fall through if two platform digits don't fit into a long
default: return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2); default: return PyLong_Type.tp_as_number->nb_{{op.lower()}}(op1, op2);
} }
return PyLong_FromLong(a {{c_op}} b); {{if c_op == '%'}}
if (unlikely(size < 0)) {
x = (-a) % b;
if (x) x = b - x;
} else {
x = a % b;
}
{{else}}
x = a {{c_op}} b;
{{endif}}
return PyLong_FromLong(x);
} }
#endif #endif
......
...@@ -22,6 +22,10 @@ def mod_obj_10(int2): ...@@ -22,6 +22,10 @@ def mod_obj_10(int2):
1 1
>>> mod_obj_10(1) >>> mod_obj_10(1)
1 1
>>> (-1) % 10
9
>>> mod_obj_10(-1)
9
>>> 9 % 10 >>> 9 % 10
9 9
>>> mod_obj_10(9) >>> mod_obj_10(9)
...@@ -30,30 +34,42 @@ def mod_obj_10(int2): ...@@ -30,30 +34,42 @@ def mod_obj_10(int2):
0 0
>>> mod_obj_10(10) >>> mod_obj_10(10)
0 0
>>> (-10) % 10
0
>>> mod_obj_10(-10)
0
>>> (-12) % 10
8
>>> mod_obj_10(-12)
8
>>> 10002 % 10 >>> 10002 % 10
2 2
>>> mod_obj_10(10002) >>> mod_obj_10(10002)
2 2
>>> int((2**25) % 10)
2
>>> int(mod_obj_10(2**25))
2
>>> int((-2**25) % 10)
8
>>> int(mod_obj_10(-2**25))
8
>>> int((2**50) % 10) >>> int((2**50) % 10)
4 4
>>> int(mod_obj_10(2**50)) >>> int(mod_obj_10(2**50))
4 4
>>> int((-2**50) % 10)
6
>>> int(mod_obj_10(-2**50))
6
>>> int((2**200) % 10) >>> int((2**200) % 10)
6 6
>>> int(mod_obj_10(2**200)) >>> int(mod_obj_10(2**200))
6 6
>>> (-1) % 10 >>> int((-2**200) % 10)
9 4
>>> mod_obj_10(-1) >>> int(mod_obj_10(-2**200))
9 4
>>> (-10) % 10
0
>>> mod_obj_10(-10)
0
>>> (-12) % 10
8
>>> mod_obj_10(-12)
8
""" """
int1 = int2 % 10 int1 = int2 % 10
return int1 return int1
......
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