'Access an element of a binary number in python

Given such a binary number, I would like to access each element in the number. For example, I use the following code to access the 3rd element:

bin(125) # '0b1111101'
bin(125)[::-1][3]

Yes, it works. But I am not sure whether this is a good way or not. It looks dangerous and I wonder if there are other better, more efficient, ways to access each element of binary numbers.



Solution 1:[1]

Your solution isn't really "dangerous," but there is a generally better way to access the nth binary digit of a number (which should work in most languages as a bonus): bitwise operations.

Solution (in Python)

You can access the binary digit with index n (with the right-most digit having index 0) of any number num using the following code:

digit = (num & (1 << n)) >> n

If you want this data as a string, you can add digit = str(digit) afterwards.

Explanation

Filtering Numbers Using & ("bitwise and")

The & operation takes two binary numbers and gives back a third binary number with 1s only in those positions where both of the original numbers had 1s.

You can use this property to "fish out" (or "mask out") the value of any binary digit of any number. For example, if we wanted to figure out the value of the 4th binary digit of the number 51:

  1 1 0 0 1 1 (51 in binary)
& 0 1 0 0 0 0 (filter value - see below)
-------------
  0 1 0 0 0 0 (result)

The "filter" value above is a number that we build using our knowledge of which binary digit we want to check. Since we want the digit at index 4, we use a number consisting of all 0's, except for a 1 in the 4th position (again, counting from the right, and starting from 0).

Since our filter value only has a 1 in the 4th position, we know that our result will have 0s in every position except the 4th position. The 4th position could be a 0 or a 1, depending on the other number.

This is fine on paper, but how do we obtain the filter value based on the index? For this we use another bitwise operation: left shift.

Constructing A Filter Using << ("bitwise left shift")

The left shift operation essentially pads a number with a certain number of 0's on the right side. For example, here's 1 << 4:

        1 (binary)
<<      4 (decimal)
---------
1 0 0 0 0 (binary)

This gives us a way to construct the filter value using only the digit's index: If we want a number with a 1 in position n, and 0s everywhere else, we can build it using 1 << n.

Fixing The Result Using >> ("bitwise right shift")

Finally, we need to convert the result to either a 0 or a 1. Since the value we "fish out" still has 0s on the right side (see the bitwise & computation above), its actual value is either 0 or 2 ** n, not 0 or 1.

To convert the value to a 0 or a 1, we just right-shift (>>) the result by the index number (n):

   0 1 0 0 0 0 (binary)
>>           4 (decimal)
--------------
           0 1 (binary)
             1 (discard leading 0s)

Right shift does the opposite operation of left shift: it removes 0s from the right side. The 0s on the left side we can just discard, since they don't contribute to the number's value.

Summary

An expanded form of the solution above could look like this:

filter = 1 << n
result = num & filter
digit = result >> n

Any time you're working with binary digits, consider using bitwise operations. They're really useful.

Solution 2:[2]

format strings if you're lazy:

f'{125:b}'[::-1] # python 3.6+ formatted string literal
# '1011111'

# otherwise str.format()

'{:b}'.format(125)[::-1]
# '1011111'

Then index the bit you want.

If not this way, you can always bitshift and mask like you would in C/C++. Depends how often you see the operation happening, or perhaps readability. But once its stringified and memoized, it's O(1) access anyway. Also, this is no longer dangerous with the '0b' at the end.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Michael
Solution 2