On Apr 18, 5:26 pm, Bob Greschke <[EMAIL PROTECTED]> wrote: > On 2008-04-18 14:37:21 -0600, Ross Ridge > <[EMAIL PROTECTED]> said: > > > > > Bob Greschke <[EMAIL PROTECTED]> wrote: > >> I'm reading 3-byte numbers from a file and they are signed (+8 to > >> -8million). This seems to work, but I'm not sure it's right. > > >> # Convert the 3-characters into a number. > >> Value1, Value2, Value3 = unpack(">BBB", Buffer[s:s+3]) > >> Value = (Value1*65536)+(Value2*256)+Value3 > >> if Value >= 0x800000: > >> Value -= 0x1000000 > >> print Value > > >> For example: > >> 16682720 = -94496 > > >> Should it be Value -= 0x1000001 so that I get -94497, instead? > > > Your first case is correct, "Value -= 0x1000000". The value 0xFFFFFFF > > should be -1 and 0xFFFFFFF - 0x1000000 == -1. > > > An alternative way of doing this: > > > Value = unpack(">l", Buffer[s:s+3] + "\0")[0] >> 8 > > > Ross Ridge > > Good to know (never was good on the math front). > > 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).
You'd better use a more precise timing method than finger counting, such as timeit. Twice as fast is probably a gross overestimation; on my box (Python 2.5, WinXP) avoiding unpack is around 10% and 40% faster from Ross's and Grant's method, respectively: python -m timeit "for i in xrange(1000):from3Bytes_bob(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 1.02 msec per loop python -m timeit "for i in xrange(1000):from3Bytes_grant(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 1.43 msec per loop python -m timeit "for i in xrange(1000):from3Bytes_ross(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 1.12 msec per loop ### bin.py ########################################## from struct import unpack def from3Bytes_bob(s): Value = (ord(s[0])<<16) + (ord(s[1])<<8) + ord(s[2]) if Value >= 0x800000: Value -= 0x1000000 return Value def from3Bytes_grant(s): if ord(s[0]) & 0x80: s = '\xff'+s else: s = '\x00'+s return unpack('>i',s)[0] def from3Bytes_ross(s): return unpack(">l", s + "\0")[0] >> 8 > 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 wasn't planning on making this discovery today! :) > > Bob If you are running this on a 32-bit architecture, get Psyco [1] and add at the top of your module: import psyco; psyco.full() Using Psyco in this scenatio is up to 70% faster: python -m timeit "for i in xrange(1000):from3Bytes_bob(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 624 usec per loop python -m timeit "for i in xrange(1000):from3Bytes_grant(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 838 usec per loop python -m timeit "for i in xrange(1000):from3Bytes_ross(s)" \ -s "from bin import *; s=pack('>i',1234567)[1:]" 1000 loops, best of 3: 834 usec per loop George [1] http://psyco.sourceforge.net/ -- http://mail.python.org/mailman/listinfo/python-list