2's complement conversion. Is this right?

Ivan Illarionov ivan.illarionov at gmail.com
Sat Apr 19 00:45:54 EDT 2008


On Fri, 18 Apr 2008 22:30:45 -0500, Grant Edwards wrote:

> On 2008-04-18, Bob Greschke <bob at passcal.nmt.edu> wrote:
> 
>> However, in playing around with your suggestion and Grant's code I've
>> found that the struct stuff is WAY slower than doing something like
>> this
>>
>>  Value = (ord(Buf[s])*65536)+(ord(Buf[s+1])*256)+ord(Buf[s+2]) if Value
>>  >= 0x800000:
>>      Value -= 0x1000000
>>
>> This is almost twice as fast just sitting here grinding through a few
>> hundred thousand conversions (like 3sec vs. ~5secs just counting on my
>> fingers - on an old Sun...it's a bit slow).  Replacing *65536 with <<16
>> and *256 with <<8 might even be a little faster, but it's too close to
>> call without really profiling it.
> 
> I didn't know speed was important.  This might be a little faster
> (depending on hardware):
> 
>   Value = (ord(Buf[s])<<16) | (ord(Buf[s+1])<<8) | ord(Buf[s+2])
> 
> It also makes the intention a bit more obvious (at least to me).
>   
> A decent C compiler will recognize that <<16 and <<8 are special and
> just move bytes around rather than actually doing shifts.  I doubt the
> Python compiler does optimizations like that, but shifts are still
> usually faster than multiplies (though, again, a good compiler will
> recognize that multiplying by 65536 is the same as shifting by 16 and
> just move bytes around).

So why not put it in C extension?

It's easier than most people think:

<code>
from3bytes.c
============
#include <Python.h>

PyObject* 
from3bytes(PyObject* self, PyObject* args)
{
    const char * s;
    int len;
    if (!PyArg_ParseTuple(args, "s#", &s, &len))
        return NULL;
    long n = (s[0]<<16) | (s[1]<<8) | s[2];
    if (n >= 0x800000)
        n -= 0x1000000;
    return PyInt_FromLong(n);
}

static PyMethodDef functions[] = {
    {"from3bytes",    (PyCFunction)from3bytes, METH_VARARGS},
    {NULL, NULL, 0, NULL},
};


DL_EXPORT(void)
init_from3bytes(void)
{
    Py_InitModule("_from3bytes", functions);
}

buildme.py
==========
import os
import sys
from distutils.core import Extension, setup

os.chdir(os.path.dirname(os.path.abspath(__file__)))
sys.argv = [sys.argv[0], 'build_ext', '-i']
setup(ext_modules = [Extension('_from3bytes', ['from3bytes.c'])])
</code>

'python buildme.py' will create '_from3bytes.so' file
'from _from3bytes import from3bytes' will import C-optimized function

Hope this helps.

-- 
Ivan Illarionov



More information about the Python-list mailing list