简体   繁体   中英

Extracting runtime number of bits from integer

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 ie we right shift based on known fixed number of bits being anded ie 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.

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:]

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 .

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

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