2's complement conversion. Is this right?

Steve Holden steve at holdenweb.com
Mon Apr 21 17:20:15 EDT 2008


Bob Greschke wrote:
> On 2008-04-21 14:50:13 -0600, Ivan Illarionov <ivan.illarionov at gmail.com> said:
> 
>> On 22 апр, 00:10, Ivan Illarionov <ivan.illario... at gmail.com>  wrote:
>>> On 20 ÁÐÒ, 04:10, George Sakkis <george.sak... at gmail.com> w
>> rote:
>>>
>>>
>>>> On Apr 18, 9:36 pm, Ross Ridge <rri... at caffeine.csclub.uwaterloo.ca>
>>>> wrote:
>>>>> Ross Ridge <rri... at caffeine.csclub.uwaterloo.ca> said:
>>>>>> If you have Python 2.5, here's a faster version:
>>>>>> from struct import *
>>>>>> unpack_i32be = Struct(">l").unpack
>>>>>> def from3Bytes_ross2(s):
>>>>>> return unpack_i32be(s + "\0")[0] >> 8
>>>>> Bob Greschke  <b... at passcal.nmt.edu> wrote:
>>>>>> That's not even intelligible.  I wanna go back to COBOL. :)
>>>>> It's the same as the previous version except that it "precompiles"
>>>>> the struct.unpack() format string.  It works similar to the way Python
>>>>> handles regular expressions.
>>>> I didn't know about the Struct class; pretty neat. It's amazing that
>>>> this version without Psyco is as fast Bob's version with Psyco! Adding
>>>> Psyco to it though makes it *slower*, not faster. So here's how I'd
>>>> write it (if I wanted or had to stay in pure Python):
>>>> try: import psyco
>>>> except ImportError:
>>>> from struct import Struct
>>>> unpack_i32be = Struct(">l").unpack
>>>> def from3Bytes(s):
>>>> return unpack_i32be(s + "\0")[0] >> 8
>>>> else:
>>>> def from3Bytes(s):
>>>> Value = (ord(s[0])<<16) + (ord(s[1])<<8) + ord(s[2])
>>>> if Value >= 0x800000:
>>>> Value -= 0x1000000
>>>> return Value
>>>> psyco.bind(from3Bytes)
>>>> HTH,
>>>> George
>>> I was able to get even faster pure-python version using array module:
>>>
>>> a = array.array('l', ''.join(('\0' + s[i:i+3] for i in xrange(0,
>>> len(s), 3))))
>>> if sys.byteorder == 'little':
>>> a.byteswap()
>>>
>>> It actually moves bytes around on C level.
>>>
>>> test code:
>>> import struct
>>> import array
>>> import sys
>>>
>>> unpack_i32be = struct.Struct(">l").unpack
>>> s = ''.join(struct.pack('>i', 1234567)[1:]*1000)
>>>
>>> def from3bytes_ord(s):
>>> values = []
>>> for i in xrange(0, len(s), 3):
>>> Value = (ord(s[i])<<16) | (ord(s[i+1])<<8) | ord(s[i+2])
>>> if Value >= 0x800000:
>>> Value -= 0x1000000
>>> values.append(Value)
>>> return values
>>>
>>> def from3bytes_struct(s):
>>> return [unpack_i32be(s[i:i+3] + "\0")[0] >> 8 for i in xrange(0,
>>> len(s), 3)]
>>>
>>> def from3bytes_array(s):
>>> a = array.array('l', ''.join(('\0' + s[i:i+3] for i in xrange(0,
>>> len(s), 3))))
>>> if sys.byteorder == 'little':
>>> a.byteswap()
>>> return a.tolist()
>>>
>>> from timeit import Timer
>>>
>>> t1 = Timer("from3bytes_ord(s)", "from __main__ import s,
>>> from3bytes_ord")
>>> t2 = Timer("from3bytes_struct(s)", "from __main__ import s,
>>> from3bytes_struct")
>>> t3 = Timer("from3bytes_array(s)", "from __main__ import s,
>>> from3bytes_array")
>>>
>>> print 'ord:\t', t1.timeit(1000)
>>> print 'struct:\t', t2.timeit(1000)
>>> print 'array:\t', t3.timeit(1000)
>>>
>>> Output:
>>> ord:    7.08213110884
>>> struct: 3.7689164405
>>> array:  2.62995268952
>>>
>>> Inspired by Guido's essayhttp://www.python.org/doc/essays/list2str/
>> And even faster:
>> a = array.array('i', '\0' + '\0'.join((s[i:i+3] for i in xrange(0,
>> len(s), 3))))
>> if sys.byteorder == 'little':
>>     a.byteswap()
>>
>> I think it's a fastest possible implementation in pure python
> 
> Geeze! :)  How did struct get so fast?  I'm guessing there have been 
> improvements since 2.3 (which is what I've been working on).  I'm going 
> to be able to go back to my IBM PC XT pretty soon. :)
> 
> Thanks!
> 
Yes, Bob Ippolito spent quite a bit of time improving it at the Need for 
Speed sprint shortly before the 2.4 (?) release. It shows.

regards
  Steve
-- 
Steve Holden        +1 571 484 6266   +1 800 494 3119
Holden Web LLC              http://www.holdenweb.com/




More information about the Python-list mailing list