2's complement conversion. Is this right?

Ivan Illarionov ivan.illarionov at gmail.com
Mon Apr 21 16:50:13 EDT 2008


On 22 апр, 00:10, Ivan Illarionov <ivan.illario... at gmail.com> wrote:
> On 20 ÁÐÒ, 04:10, George Sakkis <george.sak... at gmail.com> wrote:
>
>
>
> > 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



More information about the Python-list mailing list