按位语句的说明

Clarification of a bitwise statement

下面条件 if(a & (a-1)/2) 在 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;
}

这里我没明白/运算符的意思。条件中的除法运算符是什么意思?

除法运算符 / 简单地将左侧除以右侧。在这种情况下,右侧是 2,因此它将 a-1 右移一位(算术移位,对整数进行符号扩展)。

因此整个表达式计算 - 对于 a>=0 - a((a-1)>>1) 是否都设置了任何相同的位(在这种情况下 & 将产生一个非零值)。对于 a<0 见最后的评论。

下面是一些测试代码:

#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);
}

这给出了

  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 ...

这会检测以下任一数字:

  • 有两个或多个相邻的二进制 1 或;

  • 是负数,但不是MININT

方法如下:

  • 如果 a>=0,则 (a-1)/2 == a/2(因为四舍五入总是朝向零)。所以这等效于(对于 a>=0a & (a>>1),如果 a 中任何位右边的位被设置,即如果有两个或更多相邻的位。

  • 如果 a<0a!=MININT,(因此 1 作为其 MSB),则 (a-1) 也必须为负且小于-1,所以 (a-1)/2 也必须是负数(因此 1 作为它的 MSB),在这种情况下 a & ((a-1)/2)) 是非零的,因为它的 MSB 也必须是 1。

  • 如果a==MININT,那么a-1就是MAXINT,所以(a-1)/2没有位都是1.

a减1除以2再进行位与运算

在表达式 a & (a - 1) / 2 中有一个按位与运算符和一个除法运算符。将它们一起使用是非常不寻常的。因此,我不知道优先级是什么(它是将 a-1 除以 2 然后按位执行 a 和 a,还是按位执行 a 和 a-1,然后将结果除以二)。我实际上不关心优先级是什么,因为我不知道编写代码的程序员假定它的优先级是什么。

如果你看到这样的代码,你需要找出它的作用,你需要找出它的意图,如果两者相同你添加括号以明确意图,如果它们不一样你发现了一个错误并弄清楚它如何影响程序以及如何处理它。

对于非负值,除以2相当于右移1位。对于负值,它不是等价的,但我怀疑代码的作者并不打算使用负值。

(请注意,这种不等价与奇异的非 2 补码体系结构或算术筛选无关。在 C 和 C++ 语言中,有符号除法需要向 0 舍入,这使得无法实现有符号除法通过对 2 的补码架构负值的简单移位。需要 post 移位校正。)

现在,至于整个 a & (a - 1) / 2 表达式在做什么...让我们限制只考虑非负值。

减 1 相当于反转数字中所有尾随 0 位,然后反转最后(最低有效)1 位。除以2相当于右移1位

&操作的上下文中,整个事情等同于:杀死a中的最后1位,将整个事情右移1位和&它与原始值。

在这种情况下,我看不出取消最后 1 位的意义。看起来对于正值,整个事情等同于 a & (a / 2)(即 a & (a >> 1))),它只是检测原始 a.[=17= 中是否有两个相邻的 1 位]

在条件 / 中运算符只是做除法。唯一重要的是条件中的结果是 0(假)还是非 0(真)。

至于该程序实际执行的操作,它看起来与二进制数学相关,因此您应该询问对此了解更多的人。