简体   繁体   中英

How to improve Python code for swapping bits of a 32-bit integer

Swap bits - Coding interview question

A few days ago, I came across the following coding interview question (using Python ).

Problem:

Given a 32-bit integer, swap the 1st and 2nd bit, 3rd and 4th bit, up til the 31st and 32nd bit.

Here's some starting code and an example:

def swap_bits(num):
    # Fill this in.

print(f"0b{swap_bits(0b10101010101010101010101010101010):032b}")
# 0b01010101010101010101010101010101

My Solution:

def swap_bits(num):
    num_out = 0
    for ii in range(16):
        num_out += (num & (2**(2*ii))) << 1
        num_out += (num & (2**(2*ii+1))) >> 1
    return num_out

print(f"0b{swap_bits(0b10101010101010101010101010101010):032b}")

# Output: 
# 0b01010101010101010101010101010101

My Question to You:

Do you have any suggestions for improvement, in terms of efficiency, length of code, readability, or whatever. I will highly appreciate your feedback. Thanks!

You don't need a loop for this (well, you must not use a loop for this, in a coding interview), just a couple of binary operators:

>>> n = 752846942
>>> bin(n)
'0b101100110111111000100001011110'
>>> bin(((n >> 1) & 0x55555555) | ((n & 0x55555555) << 1))
'0b011100111011110100010010101101'

I added a leading 0 to the last number, to make the result more easily comparable to n.


What's the trick?

Consider your number as a vector of bits. Exchanging pairs of bits is equivalent to moving all even-numbered bits one position to the left, and all odd-numbered bits one position to the right (assuming bit numbering start at 0, begining with the LSB on the right).

Moving to the left and to the right is just a binary shift: n << 1 and n >> 1 . But if I simply do (n << 1) | (n >> 1) (n << 1) | (n >> 1) , I will move all bits, and the result will be wrong. So, first select which bits you want: the even bits are 0x55555555 & n , the odd bits are n & 0xaaaaaaaa .

So a possibility is:

((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1)

Another way is to select bits after the shift but before the binary or:

((n << 1) & 0xaaaaaaaa) | ((n >> 1) & 0x55555555)

Since the bit parity is reversed by the shift, I just have to swap the constants 0x55555555 and 0xaaaaaaaa.

To get the same constant on both side of the binary or, I select before the shift on one side, and after on the other.

You can definitely get rid of the exponentiation which is costly. It's possible to compress it more but as long as every operator is binary the complexity stays the same.

# to keep the code readable
def swapBits(n, p1, p2): 

    ''' Move p1'th to rightmost side '''
    bit1 = (n >> p1) & 1

    ''' Move p2'th to rightmost side '''
    bit2 = (n >> p2) & 1

    ''' XOR the two bits '''
    x = (bit1 ^ bit2) 

    ''' Put the xor bit back to their  
        original positions '''
    x = (x << p1) | (x << p2) 

    ''' XOR 'x' with the original number  
        so that thetwo sets are swapped '''
    result = n ^ x 
    return result 

n = 11
print(bin(n))
k = 0
for i in range(32):
    n = swapBits(n, k, k+1)
    k+= 2

print(n)
print(bin(n))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM