Я смотрел серию лекций в разделе "Бит-хакинг" и наткнулся на следующую оптимизацию для поиска минимум двух целых чисел:
return x ^ ((y ^ x) & -(x > y))
Говорят, что быстрее:
if x < y:
return x
else:
return y
Поскольку функция min
может обрабатывать не более двух целых чисел (поплавки, строки, списки и даже настраиваемые объекты), я предположил, что вызов min(x, y)
займет больше времени, чем оптимизированный бит-хак выше. К моему удивлению, они были почти идентичны:
>>> python -m timeit "min(4, 5)"
1000000 loops, best of 3: 0.203 usec per loop
>>> python -m timeit "4 ^ ((5 ^ 4) & -(4 > 5))"
10000000 loops, best of 3: 0.19 usec per loop
Это верно даже для чисел, больших 255
(предварительно выделенные целые объекты на основе python)
>>> python -m timeit "min(15456, 54657)"
10000000 loops, best of 3: 0.191 usec per loop
python -m timeit "15456 ^ ((54657 ^ 15456) & -(54657 > 15456))"
10000000 loops, best of 3: 0.18 usec per loop
Как можно так быстро и оптимизировать такую многофункциональную функцию, как min
?
Примечание. Я выполнил указанный выше код с помощью Python 3.5. Я предполагаю, что это то же самое для Python 2.7+, но не протестировало
Я создал следующий модуль c:
#include <Python.h>
static PyObject * my_min(PyObject *self, PyObject *args){
const long x;
const long y;
if (!PyArg_ParseTuple(args, "ll", &x, &y))
return NULL;
return PyLong_FromLong(x ^ ((y ^ x) & -(x > y)));
}
static PyMethodDef MyMinMethods[] =
{
{ "my_min", my_min, METH_VARARGS, "bit hack min"
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initmymin(void)
{
PyObject *m;
m = Py_InitModule("mymin", MyMinMethods);
if (m == NULL)
return;
}
Скомпилировал его и установил в мою систему (машина Ubuntu VM). Затем я запустил следующее:
>>> python -m timeit 'min(4, 5)'
10000000 loops, best of 3: 0.11 usec per loop
>>> python -m timeit -s 'import mymin' 'mymin.my_min(4,5)'
10000000 loops, best of 3: 0.129 usec per loop
Хотя я понимаю, что это машина VM, не должно быть большего разрыва во времени выполнения, когда "бит-хакинг" будет выгружен в native c?