2's complement conversion. Is this right?

Bob Greschke bob at passcal.nmt.edu
Fri Apr 18 18:41:34 EDT 2008


On 2008-04-18 16:04:37 -0600, George Sakkis <george.sakkis at gmail.com> said:

> On Apr 18, 5:26 pm, Bob Greschke <b... at passcal.nmt.edu> wrote:
> 
>> On 2008-04-18 14:37:21 -0600, Ross Ridge
>> <rri... at caffeine.csclub.uwaterloo.ca> said:
>> 
>> 
>> 
>>> Bob Greschke  <b... at passcal.nmt.edu> 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 0xFFFFF
> FF
>>> should be -1 and 0xFFFFFFF - 0x1000000 == -1.
>> 
>>> An alternative way of doing this:
>> 
>>>    Value = unpack(">l", Buffer[s:s+3] + "\0")[0] >> 8
>> 
>>>                                    R
> oss 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/

I'm on a Solaris 8 with Python 2.3.4 and when crunching through, 
literally, millions and millions of samples of seismic data fingers 
point out the difference nicely. :)  I'll look into this more on some 
of our bigger better faster machines (there is no -m option for timeit 
on the Sun :).  The Sun is just what I develop on.  If stuff runs fast 
enough to keep me awake on there over an ssh'ed X11 connection it 
should run even better on the real field equipment (Macs, Linuxes, 
WinXPs).

Never heard of Psyco.  That's nice!

Thanks!

Bob






More information about the Python-list mailing list