2's complement conversion. Is this right?
Ivan Illarionov
ivan.illarionov at gmail.com
Tue Apr 22 00:04:46 EDT 2008
On Mon, 21 Apr 2008 16:10:05 -0700, George Sakkis wrote:
> On Apr 21, 5:30 pm, Ivan Illarionov <ivan.illario... at gmail.com> wrote:
>
>> On 22 ÁÐÒ, 01:01, Peter Otten <__pete... at web.de> wrote:
>>
>> > Ivan Illarionov wrote:
>> > > 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
>>
>> > Clever, but note that it doesn't work correctly for negative numbers.
>> > For those you'd have to prepend "\xff" instead of "\0".
>>
>> > Peter
>>
>> Thanks for correction.
>>
>> Another step is needed:
>>
>> 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()
>> result = [n if n < 0x800000 else n - 0x1000000 for n in a]
>>
>> And it's still pretty fast :)
>
> Indeed, the array idea is paying off for largeish inputs. On my box
> (Python 2.5, WinXP, 2GHz Intel Core Duo), the cutoff point where
> from3Bytes_array becomes faster than from3Bytes_struct is close to 150
> numbers (=450 bytes).
>
> The struct solution though is now almost twice as fast with Psyco
> enabled, while the array doesn't benefit from it. Here are some numbers
> from a sample run:
>
> *** Without Psyco ***
> size=1
> from3Bytes_ord: 0.033493
> from3Bytes_struct: 0.018420
> from3Bytes_array: 0.089735
> size=10
> from3Bytes_ord: 0.140470
> from3Bytes_struct: 0.082326
> from3Bytes_array: 0.142459
> size=100
> from3Bytes_ord: 1.180831
> from3Bytes_struct: 0.664799
> from3Bytes_array: 0.690315
> size=1000
> from3Bytes_ord: 11.551990
> from3Bytes_struct: 6.390999
> from3Bytes_array: 5.781636
> *** With Psyco ***
> size=1
> from3Bytes_ord: 0.039287
> from3Bytes_struct: 0.009453
> from3Bytes_array: 0.098512
> size=10
> from3Bytes_ord: 0.174362
> from3Bytes_struct: 0.045785
> from3Bytes_array: 0.162171
> size=100
> from3Bytes_ord: 1.437203
> from3Bytes_struct: 0.355930
> from3Bytes_array: 0.800527
> size=1000
> from3Bytes_ord: 14.248668
> from3Bytes_struct: 3.331309
> from3Bytes_array: 6.946709
>
>
> And here's the benchmark script:
>
> import struct
> from array import array
>
> def from3Bytes_ord(s):
> return [n if n<0x800000 else n-0x1000000 for n in
> ((ord(s[i])<<16) | (ord(s[i+1])<<8) | ord(s[i+2])
> for i in xrange(0, len(s), 3))]
>
> unpack_i32be = struct.Struct('>l').unpack 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('l', ''.join('\0' + s[i:i+3]
> for i in xrange(0,len(s), 3)))
> a.byteswap()
> return [n if n<0x800000 else n-0x1000000 for n in a]
>
>
> def benchmark():
> from timeit import Timer
> for n in 1,10,100,1000:
> print ' size=%d' % n
> # cycle between positive and negative buf =
> ''.join(struct.pack('>i', 1234567*(-1)**(i%2))[1:]
> for i in xrange(n))
> for func in 'from3Bytes_ord', 'from3Bytes_struct',
> 'from3Bytes_array':
> print ' %s: %f' % (func,
> Timer('%s(buf)' % func ,
> 'from __main__ import %s; buf=%r' % (func,buf)
> ).timeit(10000))
>
>
> if __name__ == '__main__':
> s = ''.join(struct.pack('>i',v)[1:] for v in
> [0,1,-2,500,-500,7777,-7777,-94496,98765,
> -98765,8388607,-8388607,-8388608,1234567])
> assert from3Bytes_ord(s) == from3Bytes_struct(s) ==
> from3Bytes_array(s)
>
> print '*** Without Psyco ***'
> benchmark()
>
> import psyco; psyco.full()
> print '*** With Psyco ***'
> benchmark()
>
>
> George
Comments:
You didn't use the faster version of array approach:
''.join('\0' + s[i:i+3] for i in xrange(0,len(s), 3))
is slower than
'\0' + '\0'.join(s[i:i+3] for i in xrange(0,len(s), 3))
To Bob Greschke:
Struct is fast in Python 2.5 with struct.Struct class.
Array approach should work with Python 2.3 and it's probably the fastest
one (without psyco) with large inputs:
def from3bytes_array(s):
a = array.array('i', '\0' + '\0'.join([s[i:i+3]
for i in xrange(0, len(s), 3)]))
a.byteswap() # if your system is little-endian
return [n >= 0x800000 and n - 0x1000000 or n for n in a]
--
Ivan
More information about the Python-list
mailing list