Bob Greschke wrote: > On 2008-04-18 23:35:12 -0600, Ivan Illarionov <[EMAIL PROTECTED]> > said: > >> 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); >> } > > No thanks. Being able to alter and install these programs on whatever > computer they are installed on is more important than speed. I went > down the C-extension path years ago and it turned into a big mess. > Everything has to run on Sun's, Mac's, Linux and Windows without any > major hassels if they have to be changed. I can't reley on everything > the program needs to be rebuilt being installed beyond Python and > Tkinter (and pySerial and PIL for a couple of programs), which they > need to run. So no compiling and everything is in one file, in case a > new version has to be upgraded by a user by emailing it to them while > they're sitting on some mountain in Tibet. Just unzip, stick the .py > somewhere logical, (usually) double-click, and they are off and running. > > Bob
Just for fun, here's a way to convert lots of 3-byte integers using PIL: from PIL import Image import array def int3_pil(s, trafo="\x00"*128+"\xff"*128): n = len(s)//3 im = Image.new("RGB", (n, 1)) im.fromstring(s) hi, mid, lo = im.split() sign = Image.new("L", (n, 1)) sign.fromstring(hi.tostring().translate(trafo)) im = Image.merge("RGBA", (lo, mid, hi, sign)) a = array.array("i") a.fromstring(im.tostring()) return a.tolist() Not as fast as I had hoped, though. Also, it needs some work to make it independent of the processor architecture. Peter -- http://mail.python.org/mailman/listinfo/python-list