I need to extract some bits from an integer. However how many bits to be extracted is not fixed.
For example a certain code is generating 2 numbers a and b. What I want is a code that could do
c = a[b-1:0]
One of the methods I read about on the web is w say b is a fixed value 3, a simple method to do is
c=bin (a >> 0 & 0b111 )
But this could be done if value of b is fixed 3 i.e we right shift based on known fixed number of bits being anded i.e 3.
But what if the "3" is not fixed? During run time I may need lower 4 bits or 3 bits or 2 bits...anything.
I thing I tried and hoped it would work is
x = bin(a)
c= x[b-1:0]
But even this doesn't work.
Some of your code is trying to access the bits of an integer using slice notation ([:]) but that only works with sequences, not integers.
First you need to decide if you want to work with a string representation of your number in binary, or an integer representation, and be consistent about that. Let's start with a string representation in binary. a is the input number, b is the number of bits.
>>> a = 35
>>> x = bin(a)
>>> x
'0b100011'
Now you want a string representation in binary of the integer that is the rightmost b positions of this string:
>>> b = 3
>>> x[-b:]
'011'
Deprived of its 0b prefix, this string of 3 digits could mean anything. Some examples: in binary, 3; in decimal, 11; in octal 9; in hex, 17. We know from reading the code that it is part of the output from a bin() call, but the string doesn't carry that information around with it. The 3 digits mean whatever you intend them to mean.
If you want to convert that into something you can do arithmetic with, you call int() to convert it back to an integer. But because int() can't tell that the representation is supposed to be binary, do this:
>>> int(x[-b:],2)
3
The 2 passed as the second parameter to int() specifies what base the string is supposed to be in. It's not specifying a conversion: it's specifying an interpretation. It's optional, but if you leave it out then int() will use the default base, which is of course 10.
>>> int(x[-b:])
11
This happens because without any indication of the base, 011 means "eleven, with a leading zero". And int() converts a string to an integer: just integer, not base-10 integer. The internal representation of integer is only converted to base 10 when you ask the interpreter to display it. (Internally, Python integers actually use base 2**30, but most of us never have to think about that much, and I recommend you don't either.)
Now consider just working with integers. If the number of bits you want to mask off is b then (as johnrsharpe points out), you can get the corresponding mask using (2**b - 1):
>>> 2**b - 1
7
Just to demonstrate this is what you actually want:
>>> bin(2**b - 1)
'0b111'
Then you can use the bitwise & operator to get the digits you want. This works sort of opposite to the string method: instead of chopping off the 3 digits that you want, you instead use & to set the digits you don't want to zero:
a = 100011
b = 000111 &
------
000011
Then you can obtain the result directly without having to go through a string conversion and taking slices and converting back to integer:
>>> a & 2**b - 1
3
As you can see this gives the same result in one step. In your question I also see a right shift operator >> but because you are shifting zero positions it does nothing. If you also want to accept a shift quantity, say s, then in the examples above, use (a >> s) instead of a.
From the question, it is not very clear what you actually want to do, but what I understood is that you want to extract 'b' last bits from 'a'.
If two numbers are 'a' and 'b':
First, convert 'a' into binary:
x = bin(a)[2:]
Extracting last b bits from a:
p = x[len(x)-b:]
If you actually want the (lower) bits of the integer value: something like this could do it:
def getbits(value, numbits):
""" Extract the lower numbits of value. """
return value & (2 ** numbits - 1)
value = 0b010011000111
for i in range(value.bit_length()+1):
print('getbits({:012b}, {:2d}): {:12b}'.format(value, i, getbits(value, i)))
Output:
getbits(010011000111, 0): 0
getbits(010011000111, 1): 1
getbits(010011000111, 2): 11
getbits(010011000111, 3): 111
getbits(010011000111, 4): 111
getbits(010011000111, 5): 111
getbits(010011000111, 6): 111
getbits(010011000111, 7): 1000111
getbits(010011000111, 8): 11000111
getbits(010011000111, 9): 11000111
getbits(010011000111, 10): 11000111
getbits(010011000111, 11): 10011000111
What is the easiest/fastest way to get a int in python which can be represented by all ones in binary. This is for generating N bit masks.
E.g:
If total number of bits is 4, then binary '1111' or int 15
If total number of bits is 8 then, binary '1111 1111' or 255
I was under the impression ~0 is for that purpose, looks like that is not the case or I am missing something.
it's very easy to achieve with bit shifting:
>>> (1<<4)-1
15
shifting 4 times 1 to the left gives you 0b10000, substract 1 you get 0b1111 aka 15.
(the int("1"*4,2) method is overkill because it involves building a string and parsing it back)
I have a 64-bit hex number inputting into my script
0x0000040800000000. I want to take this number and extract bits 39:32.
How is this possible? I have been parsing individual parts of a string and have ended up in a mess.
I was initially converting it into binary and parsing out sections of the string from
command_register = "".join(["{0:04b}".format(int(c,16)) for c in str(command_register)])
You simply need to first convert your hex string into an integer and then use normal maths to extract the bits.
Bit numbering is usually done from the least significant bit, i.e. the furthest right when displayed in binary is bit 0. So to extract bits 39:32 (8 consecutive bits), you would simply need a mask of 0xFF00000000. Simply AND your number and shift the result 32 bits to the right.
Using your hex value and extracting bits 39 to 32 would give you a value of 0x08. The following script shows you how:
hex_string = "0x0000040800000000"
number = int(hex_string, 16) # Convert to an integer
mask_39_to_32 = 0xFF00000000 # Suitable mask to extract the bits with
print(f"As hex: 0x{number:X}")
print()
print("Bits 39-32: xxxxxxxx")
print(f" As binary: {bin(number)[2:]:0>64s}")
print(f" Mask: {bin(mask_39_to_32)[2:]:0>64s}")
print(f"AND result: {bin(number & mask_39_to_32)[2:]:0>64s}")
print(f" Shifted: {bin((number & mask_39_to_32) >> 32)[2:]:0>64s}")
print(f" As an int: {(number & mask_39_to_32) >> 32}")
Which displays the following output:
As hex: 0x40800000000
Bits 39-32: xxxxxxxx
As binary: 0000000000000000000001000000100000000000000000000000000000000000
Mask: 0000000000000000000000001111111100000000000000000000000000000000
AND result: 0000000000000000000000000000100000000000000000000000000000000000
Shifted: 0000000000000000000000000000000000000000000000000000000000001000
As an int: 8
The mask needed for 47 to 40 would be:
Bits 47-40: xxxxxxxx
As binary: 0000000000000000111111110000000000000000000000000000000000000000
As hex: 0xFF0000000000
The use of hexadecimal simply makes it less verbose, and clearer once you get used to it. Groups of 8 bits for masks always end up as 'FF'.
The Wikipedia article on bitwise operations should help you to understand the process.
I've got an array of short/int16s that i need to convert to a padded 16 bit-string(?). I've tried using struct:
struct.pack('>H', 545)
To which i get:
'\x02!'
Whereas I need something formatted as 16 bits.
Does anyone know how to do this? I'm rather confused and know next to nothing about the binary system.
Cheers
That is 16 bits. '\x02' is 8 bits, and ! is the other 8.
Were you looking for '0000001000100001'? If so, you can do that with the format function:
>>> format(545, '016b')
'0000001000100001'
The 0 means "pad with zeros", the 16 means "show at least 16 digits", and the b means binary.
If you don't need the zero padding, you can just use bin:
>>> bin(545)
'0b1000100001'
>>> bin(545)[2:]
'1000100001'
I have been having some real trouble with this for a while. I am receiving a string of binary data in python and I am having trouble unpacking and interpreting only a 5bit subset (not an entire byte) of the data. It seems like whatever method comes to mind just simply fails miserably.
Let's say I have two bytes packed binary data, and I would like to interpret the first 10bits within the 16. How could I convert this to an 2 integers representing 5bits each?
Use bitmasks and bitshifting:
>>> example = 0x1234 # Hexadecimal example; 2 bytes, 4660 decimal.
>>> bin(example) # Show as binary digits
'0b1001000110100'
>>> example & 31 # Grab 5 most significant bits
20
>>> bin(example & 31) # Same, now represented as binary digits
'0b10100'
>>> (example >> 5) & 31 # Grab the next 5 bits (shift right 5 times first)
17
>>> bin(example >> 5 & 31)
'0b10001'
The trick here is to know that 31 is a 5-bit bitmask:
>>> bin(31)
'0b11111'
>>> 0b11111
31
>>> example & 0b11111
20
As you can see you could also just use the 0b binary number literal notation if you find that easier to work with.
See the Python Wiki on bit manipulation for more background info.