views:

65

answers:

2

Let's say I have two integers with the following binary representations:

01101010
00110101

And now I want to copy the last 3 bits from the first integer over the second one so that it becomes

00110010

What's the easiest way to do that?

(Actually, my goal is to shift the all the X+1 bits to the right one, essentially deleting the Xth bit, and keeping the X-1 bits the same -- in this case, X is 4)


The "why?":

You have a bunch of flags,

1 = 'permission x'
2 = 'permission y'
4 = 'permission z'
8 = 'permission w'

You decide that that "permission y" is no longer needed in your program, and thus shift z and w up a position (making them 2 and 4 respectively). However, now you need to update all the values in your database.... (what formula do you use?)

+5  A: 

Depending on your version of python, the way you express binary literals changes, see this question for the details.

I'm using 2.5.2, so I used this:

>>> a = int('01101010', 2)
>>> b = int('00110101', 2)
>>> mask = 07  # Mask out the last 3 bits.
>>> (b & ~mask) | (a & mask)
50
>>> int('00110010', 2)
50

Details:

(b & ~mask)  <- This keeps the first n-3 bits. (By negating the 3bit mask).
(a & mask)   <- This keeps the last 3 bits.
If you '|' (bitwise OR) them together, you get your desired result.

I didn't understand your goal in the last sentence, so I don't know how to address that :)

Stephen
More generally, `mask = (1<<(x-1))-1` I think?
Mark
@Mark : Good call, I was confused by the '3' vs '4' vs 'X+1', but I think you're right.
Stephen
Well "4" is the bit to "remove". Which means we need to keep the right "3" bits the same.
Mark
Btw, `b = a>>1` (that much I figured out was the first step, the rest I couldn't quite figure out)
Mark
@Mark: I see. +1. Glad I could help.
Stephen
@Stephen: Haha..don't worry about it. You can see this question http://stackoverflow.com/questions/3217768/ if you want some more details (the "why" bit) -- maybe I want to remove the "FIREBALL" ability sometime down the road.
Mark
+2  A: 

Based on Stephen's answer (upvote him), the solution is:

def f(pos, val):
    """
    @pos: the position of the bit to remove
    @val: the value to remove it from
    """
    mask = (1<<(pos-1))-1
    return ((val>>1) & ~mask) | (val & mask)

print f(4, int('01101010', 2)) == int('00110010', 2)
Mark