On Sat, 19 Apr 2008 04:45:54 +0000, Ivan Illarionov wrote: > On Fri, 18 Apr 2008 22:30:45 -0500, Grant Edwards wrote: > >> On 2008-04-18, Bob Greschke <[EMAIL PROTECTED]> 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.
Sorry, the right code should be: PyObject* from3bytes(PyObject* self, PyObject* args) { const char * s; int len; if (!PyArg_ParseTuple(args, "s#", &s, &len)) return NULL; long n = ((((unsigned char)s[0])<<16) | (((unsigned char)s[1])<<8) | ((unsigned char)s[2])); if (n >= 0x800000) n -= 0x1000000; return PyInt_FromLong(n); } -- http://mail.python.org/mailman/listinfo/python-list