(x & (a - 1)) + 1 vs (x & a)

一笑奈何 提交于 2020-12-13 07:44:21

问题


I was looking over trying to understand the code for this closed question, and there's a line I don't understand, performing a bitwise AND on two integers, x and a:

return (x & (a - 1)) + 1

What is the effect of the subtraction and addition in comparison with just a simple bitwise AND:

return x & a

I wrote a python script to compare the truth tables:

print("(  x,   a) => ret vs x&a")
for x in range(0, 5):
  print("")
  for a in range(0, 5):
    print("({:03b}, {:03b}) => {:03b} vs {:03b}".format(x, a, (x & (a - 1)) + 1, x & a))

Which prints:

(  x,   a) =>   r vs x&a

(000, 000) => 001 vs 000
(000, 001) => 001 vs 000
(000, 010) => 001 vs 000
(000, 011) => 001 vs 000
(000, 100) => 001 vs 000

(001, 000) => 010 vs 000
(001, 001) => 001 vs 001
(001, 010) => 010 vs 000
(001, 011) => 001 vs 001
(001, 100) => 010 vs 000

(010, 000) => 011 vs 000
(010, 001) => 001 vs 000
(010, 010) => 001 vs 010
(010, 011) => 011 vs 010
(010, 100) => 011 vs 000

(011, 000) => 100 vs 000
(011, 001) => 001 vs 001
(011, 010) => 010 vs 010
(011, 011) => 011 vs 011
(011, 100) => 100 vs 000

(100, 000) => 101 vs 000
(100, 001) => 001 vs 000
(100, 010) => 001 vs 000
(100, 011) => 001 vs 000
(100, 100) => 001 vs 100

But I can't make heads or tails of it. It looks like it results in more bits set than a simple AND, and it seems like last bit is set to 1 if the last bit of x is 0, but other than that, I'm not sure of any patterns. Maybe this is just an arbitrary choice in context of the program to massage the output.

Is there a common reason to use (x & (a - 1)) + 1 over x & a? Is this a common pattern?

UPDATE:

An example of what this reminds me of is the standard deviation formula:

In this formula the sqrt at the end balances out the squares being done. It doesn't undo or equal the square operations, because of all the addition being done in the middle--the sqrt isn't associative with addition (or whatever the term is)--but the sqrt puts the result on the same scale as they would have been without the square operations inside. I may have the technical terms wrong but that's my understanding.

This equation using AND reminds me of that. It's as if something is being done before the AND and then loosely undone at the end to get back in the same ballpark as the original answer, more or less. I thought maybe this was a common operation, cause it appeared to have a sort of balance.

So that is what I am looking for. But maybe my intuition was just wrong and no such relationship exists.


回答1:


You seem to expect two different expressions to produce the same result, as if addition and bit-level masking were invariant over operation ordering. You went to a lot of productive effort to show that they are not equivalent, and how.

I don't see where you're confused. It doesn't seem to make any more sense than if you replaced the AND operation with, say, squaring the number:

x**2
# versus
(x+1)**2 - 1

Think of AND as a mask operation: it turns off bits in a that correspond to 0s in x.

The given code computes a-1, an arithmetic operation. Then it masks off some bits, a logical operation. Finally, it adds 1, another arithmetic operation. I don't know why this is useful; that would be in the context of the original post. However, since the arithmetic can alter more than a single bit, the two expressions are not at all equivalent, as your table shows so nicely.




回答2:


This may be doing some math looking for the number of common factors of 2 or something.

if both numbers are odd, it gives the same result,

if X is even and A is odd, it gives the same result but +1.

converting the +-1 to a bit operation, we see:

the -1 will flip bits from right to left until it changes the rightmost 1 to a 0

the mask x, will set bits to 0 where x is 0

the +1 will flip bits from right to left until it changes the rightmost 0 to a 1

so a it's comparing the position of rightmost 0 in X with the rightmost 1 in A

if the 1 in A is to the right of the 0 in X we get the same result, bits between these points are flipped where masked...

Try looking at X = 1111000000001111 with various As, like 1111111100000000, and shift A left and right, or shift the mask 0s

It's some kind of collision detection maybe.



来源:https://stackoverflow.com/questions/64830164/x-a-1-1-vs-x-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!