[Tutor] [spoiler] Re: Shifting arrays as though they are a 'word'

Peter Otten __peter__ at web.de
Sat Oct 6 04:10:10 EDT 2018

Chip Wachob wrote:

> Hello,
> I was not able to find any answers in the archive on this one.
> I'm wondering if this task can be done in a better way than what I've
> attempted..
> I have an array of bytes.  Up to 64, which makes for 512 bits.
> I am reading these bytes in serially, and once I have a collection of
> them, I want to shift them by 'n' bits.  The size of the array and the
> number of bits are both variable up to the limit of 64/512.
> Now, I've played around with looping through the bytes and taking the
> LSByte and shifting it by 'n' bits using >> or << and that works for
> the first byte.  But then I need to take the next byte in the sequence
> and shift it in the opposite direction by 8-n bits using << or >>
> (opposite the LSByte direction), respectively.  Then I OR the two
> bytes and save them into the location of the LSByte and then move to
> the next byte in the sequence and so on.  While this works most of the
> time, I sometimes get strange behavior at the 'fringes' of the bytes.
> Sometimes I end up with zero, or the shift seems to 'roll over'.
> I'm thinking that maybe there's a way to treat the array / list and
> shift allowing the bits to transfer from byte to byte as needed.
> Maybe by concatenating the bytes into one huge word and then breaking
> it apart again?
> I'm thinking that you folks out there know of a built-in function, or,
> an easier and more predictable way to accomplish the same.

Here are two ways to implement the left shift:

def bitshift(b, n, byteorder="big"):
    size = len(b) + (n + 7) // 8
    shifted = int.from_bytes(b, byteorder) << n
    return shifted.to_bytes(size, byteorder)

def bitshift2(b, n):
    nbytes, nbits = divmod(n, 8)
    if nbits:
        a = [0]
        for bb in b:
            hi, lo = divmod(bb << nbits, 256)
            a[-1] |= hi
        b = bytes(a)
    return b + b"\x00" * nbytes

assert bitshift(b"\xaa\xbb", 12) == b"\x0a\xab\xb0\x00"
assert bitshift2(b"\xaa\xbb", 12) == b"\x0a\xab\xb0\x00"

More information about the Tutor mailing list