2

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.

5
  • 3
    What about this looks "dangerous"? Commented Mar 3, 2018 at 0:41
  • 4
    You can shift and mask: [(125 >> x) & 1 for x in reversed(range(7))] => [1, 1, 1, 1, 1, 0, 1] Commented Mar 3, 2018 at 0:43
  • 1
    And use int.bit_length() so you have an easy way to count. Commented Mar 3, 2018 at 1:00
  • It is dangerous, because with this way Python clips off excess 0s at the start. The example only has 7 digits so accessing bit #7 would return b. It gets worse when there are less characters than 8 in the bin string – then you'd get an IndexError. Commented Mar 3, 2018 at 1:30
  • 1
    You say you'd like to access each number. For doing what, overall? You probably shouldn't access them like that anyway. Commented Mar 3, 2018 at 1:45

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

Comments

-1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.