简体   繁体   中英

Clarification of a bitwise statement

What does the following condition if(a & (a-1)/2) mean in C?

#include <stdio.h>

int main()
{
   int a;
   scanf("%d", &a);

   if(a & (a-1)/2)
   {
      printf("Yes\n");
   }
   else{
       printf("No\n");
   }
   return 0;
}

I didn't get the meaning of / operator here. what does the division operator mean in the condition ?

The division operator / simply divides the left hand side by the right hand side. In this case the right hand side is 2, so it's shifting a-1 right by one bit (an arithmetic shift, which sign-extends the integer).

The whole expression therefore calculates - for a>=0 - whether a and ((a-1)>>1) both have any of the same bits set (in which case & will produce a non-zero value). For a<0 see the comment at the end.

Here's some test code:

#include <stdio.h>
#include <stdlib.h>

int
main (int argc, char **argv)
{
  int i;
  for (i = 0; i < 256; i++)
    {
      printf ("%3d %s\n", i, (i & (i - 1) / 2) ? "yes" : "no");
    }
  exit (0);
}

which gives

  0 no
  1 no
  2 no
  3 yes
  4 no
  5 no
  6 yes
  7 yes
  8 no
  9 no
 10 no
 11 yes
 12 yes
 13 yes
 14 yes
 15 yes
 16 no
 17 no
 18 no
 19 yes
 20 no
 21 no
 22 yes
 23 yes
 24 yes
 25 yes
 26 yes
 27 yes
 28 yes
 29 yes
 30 yes
 31 yes
 32 no
 33 no
 34 no
 ... abbreviated for clarity ...

This detects numbers that either:

  • have two or more adjacent binary 1s or;

  • are negative, but not MININT .

Here's how:

  • If a>=0 , then (a-1)/2 == a/2 (as rounding is always towards zero). So this is equivalent (for a>=0 ) to a & (a>>1) which will be one if the bit to the right of any bit in a is set, ie if there are two or more adjacent ones.

  • If a<0 and a!=MININT , (and thus have 1 as its MSB), then (a-1) must also be negative and less than -1 , so (a-1)/2 must also be negative (and thus have 1 as its MSB), in which case a & ((a-1)/2)) is non-zero because its MSB must also be 1.

  • If a==MININT , then a-1 is MAXINT , so (a-1)/2 has no bits that are both 1.

For non-negative values, division by 2 is equivalent to shifting it 1 bit to the right. For negative values it is not equivalent, but I suspect that the authors of the code did not intend it to work with negative values.

(Note that this non-equivalence has nothing to do with exotic non-2's-complement architectures or arithmetic sifts. In C and C++ language signed division is required to round towards 0, which makes it impossible to implement signed division by a simple shift for negative values on 2's complement architectures. A post-shift correction is required.)

Now, as for what the whole a & (a - 1) / 2 expression is doing... Let's restrict consideration for non-negative values only.

Subtracting 1 is equivalent to inverting all trailing 0 bits in the number and then inverting the last (least significant) 1 bit. Division by 2 is equivalent to shift right by 1 bit.

In the context of & operation, the whole thing is equivalent to: kill the last 1 bit in a , shift the whole thing to the right 1 bit and & it with the original value.

I don't see the point of killing the last 1 bit in this case. It looks like for positive values the whole thing is equivalent to a & (a / 2) (ie to a & (a >> 1)) ), which simply detects if there are two adjacent 1 bits in the original a .

它从a减去1,然后除以2,然后进行位与运算。

In the condition / operator simply does division. The only thing that matters is whether the result in condition is 0 (false) or not 0 (true).

As fot what the program actually does, it looks binary math related so you should ask someone who knows more about that.

In the expression a & (a - 1) / 2 there is a bitwise and operator, and a division operator. It is highly unusual that these are used together. Therefore, I don't know what the precedence is (does it divide a-1 by two and does a bitwise and with a, or does it do a bitwise and of a and a-1, then divide the result by two). I actually don't care what the precedence is, because I don't know what precedence the programmer writing the code assumed it would be.

If you see code like this, you need to find out what it does, you need to find out what it was intended to do, if both are the same you add parentheses to make the intent clear, and if they are not the same you have found a bug and figure out how it affects the program and what to do about it.

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