2's complement conversion. Is this right?

Bob Greschke bob at passcal.nmt.edu
Mon Apr 21 23:06:08 CEST 2008


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!




More information about the Python-list mailing list