The other day I found myself wondering how to perform bitwise rotations in Python, particular bit rotations (circular shifts). There’s lots of complex ways to do it – bitstring, bitarray, and others – but I wanted a more compact and efficient method.
Turns out it’s relatively easy… the C idiom for bitwise rotation is a good starting point, but I’ve extended it to handle an arbitrary unsigned bit string (one that is first truncated to fit in the width of the virtual “register” we’re shifting in – just so it doesn’t go totally bonkers if it gets an “impossible” value). It’s also robust enough to handle excessive rotations (where a value only n bits long is rotated more than n bits).
Here it is along with some test code:
###########################################################################
# Rotating bits (tested with Python 2.7)
from __future__ import print_function # PEP 3105
# max bits > 0 == width of the value in bits (e.g., int_16 -> 16)
# Rotate left: 0b1001 --> 0b0011
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
# Rotate right: 0b1001 --> 0b1100
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
max_bits = 16 # For fun, try 2, 17 or other arbitrary (positive!) values
print()
for i in xrange(0, max_bits*2-1):
value = 0xC000
newval = rol(value, i, max_bits)
print("0x%08x << 0x%02x --> 0x%08x" % (value, i, newval))
print()
for i in xrange(0, max_bits*2-1):
value = 0x0003
newval = ror(value, i, max_bits)
print("0x%08x >> 0x%02x --> 0x%08x" % (value, i, newval))
###########################################################################
Permalink
Thanks, needed this.
Permalink
Thanks 🙂
Permalink
Wow, thank you! Really helped.