这个按位运算如何检查 2 的幂?

Posted

技术标签:

【中文标题】这个按位运算如何检查 2 的幂?【英文标题】:How does this bitwise operation check for a power of 2? 【发布时间】:2009-06-27 20:44:00 【问题描述】:

我正在查看一些应该是微不足道的代码 - 但我的数学在这里让我很失望。

这是一个条件,它使用以下方法检查一个数字是否是 2 的幂:

if((num != 1) && (num & (num - 1)))  /* make num pow of 2 */ 

我的问题是,如何在 num 和 num - 1 之间使用按位与来确定一个数字是否是 2 的幂?

【问题讨论】:

更多信息可以在这个问题中找到:***.com/questions/600293/… 这显然取决于 num 的类型 - 这里的大多数答案都假设它是无符号整数类型,其中按位运算是明确定义的。 【参考方案1】:

2 减 1 的任何幂都是一:(2N - 1 = 111....b)

2 = 2^1.  2-1 = 1 (1b)
4 = 2^2.  4-1 = 3 (11b)
8 = 2^3.  8-1 = 7 (111b)

以 8 为例。 1000 & 0111 = 0000

所以该表达式测试一个数字是否不是 2 的幂。

【讨论】:

在 1.num=0 和 num = -2147483648 时的极端情况,如果数据类型是 int 受最小值限制。当 num==0 时,num 不是 2 次方 这个解释如何证明什么?它仅表明 2 的幂会为表达式 x & (x - 1) 生成 0,而不是相反。【参考方案2】:

好吧,第一种情况将检查 20 == 1。

对于其他情况,num & (num - 1) 发挥作用:

也就是说,如果你取任何数字,并从低位屏蔽掉位,你会得到以下两种情况之一:

    如果数字已经是 2 的幂,则减一将导致二进制数仅设置低位。使用& 将无济于事。

    以 8 为例:0100 & (0100 - 1) --> (0100 & 0011) --> 0000

    如果数字已经不是二的幂,那么减一不会触及最高位,因此结果将是至少小于num的二的最大幂。

    以 3 为例:0011 & (0011 - 1) --> (0011 & 0010) --> 0010

    以 13 为例:1101 & (1101 - 1) --> (1101 & 1100) --> 1100

所以实际的表达式会找到不是 2 的幂的所有内容,包括 20

【讨论】:

其实对特例num==1(2^0=1)的检查是不需要的。对于这种情况 (num & (num-1)) = (1 & 0) = 0 反正。 第二点的解释不正确,(num - 1) 可能是2的幂,但不一定是这样。结果总是非零的原因是因为操作可以总是在不触及最高位的情况下进行,并且至少该位会出现在输出中。 Ismael Luceno 的评论是对这一观察的更好解释 如上面 cmets 中所述,第 2 点中的陈述:“返回不大于 num 的 2 的最高幂”是不正确的。它应该更准确地阅读“它返回至少不大于num的2的最高幂”。我已对此答案进行了编辑,正在等待同行评审。【参考方案3】:

嗯,

如果您有 X = 1000,则 x-1 = 0111。而 1000 && 0111 是 0000。

每个是 2 的幂的数字 X 都有一个 x-1,在 x 的位置上有一个 0 。并且 0 和 1 的位和总是 0。

如果数字 x 不是 2 的幂,例如 0110。x-1 是 0101,and 给出 0100。

对于 0000 - 1111 内的所有组合,这会导致

   X  X-1 X && X-1  
0000 1111 0000   
0001 0000 0000 
0010 0001 0000
0011 0010 0010
0100 0011 0000
0101 0100 0100
0110 0101 0100
0111 0110 0110
1000 0111 0000
1001 1000 1000
1010 1001 1000
1011 1010 1010
1100 1011 1000
1101 1100 1100
1110 1101 1100
1111 1110 1110

而且不需要单独检查 1。

【讨论】:

但当然需要检查 0,因为 0 不是 2 的幂,但要像测试一样进行测试。 这里有几件事-首先,我认为您在一些地方使用了&&,而您的意思是&n && (n-1) 几乎在所有地方都是 1(除了 n=​​0 和 n=1,对吗?)其次,1 是 2 的幂,但“需要”取决于我们从未见过的上下文('如果幂是正的,则为真/natural”,或者反过来说,“如果恰好设置了一个位,则为真”,等等。)没什么私人的,反正这几乎是十年前的事了。【参考方案4】:

我更喜欢这种依赖二进制补码的方法:

bool checkPowTwo(int x)
    return (x & -x) == x;

【讨论】:

这个函数和返回(x & (x - 1)) == 0有同样的缺点:它返回1x = 0【参考方案5】:

很好地解释了here

此外,给出的表达式认为 0 是 2 的幂。修复该使用 !(x & (x - 1)) && x; 代替。

【讨论】:

不,那是错误的。没有 x 使得 2**x = 0。因此 x 不是 2 的幂。【参考方案6】:

判断整数是否为 2 的幂。如果(x & (x-1)) 为零,则该数字是 2 的幂。

例如, 让x 为 8(1000 二进制);然后x-1 = 7 (0111)。

if    1000
  &   0111
---------------
      0000

C程序演示:

#include <stdio.h>

void main()

    int a = 8;
    if ((a&(a-1))==0)
    
        printf("the bit is power of 2  \n");
    
    else 
    
        printf("the bit is not power of 2\n");
    

这会输出the bit is power of 2

#include <stdio.h>

void main()

    int a = 7;
    if ((a&(a-1))==0)
    
        printf("the bit is power of 2  \n");
    
    else 
    
        printf("the bit is not power of 2\n");
    

这会输出the bit is not power of 2

【讨论】:

【参考方案7】:

假设 n 是给定的数字, 如果 n 是 2 的幂 (n && !(n & (n-1)) 将返回 1 否则返回 0

【讨论】:

【参考方案8】:

当你将一个正整数减 1 时:

    如果为零,您将得到-1。 如果其最低有效位为1,则该位设置为0,其他位不变。 否则,所有低位0位都设置为1,最低位1如果设置为0,其他位不变。

案例 1:x &amp; (x - 1)0,但 x 不是 2 的幂,微不足道的反例。

情况 2 和 3:如果xx-1 没有共同的位,则表示上述两种情况下的 其他位 都为零,因此该数字只有一个1 位,因此它是 2 的幂。

如果x 为负,则此测试不适用于有符号整数的二进制补码表示,因为递减溢出或xx-1 至少有共同的符号位,这意味着x &amp; (x-1) 不是零。

要测试 2 的幂,代码应该是:

int is_power_of_2(unsigned x) 
    return x && !(x & (x - 1));

【讨论】:

【参考方案9】:
#include <stdio.h>
void powerof2(int a);
int a;

int main()

    while(1)
    
       printf("Enter any no. and Check  whether no is power of 2 or no \n");
       scanf("%d",&a);
       powerof2(a);
    

void powerof2(int a)

    int count = 0;
    int b=0;
   while(a)
   
     b=a%2;
     a=a/2;
     if(b == 1)
          count++;  
   
  if(count == 1)
   
      printf("power of 2\n");
   
  else
    printf("not power of 2\n");

【讨论】:

在某些情况下 x & ( x-1) 不起作用,但我们可以这样做 您的power2 函数只能运行一次!为什么要创建countab 全局变量? Hii Chqelie ,如果在主函数内部使用 while(1) 并且每次从 user 获取值时都会使用 printf() ,则仅是一次。 int count 和 int b 也可以作为全局变量,但初始化为零 while(1) printf("Enter any value for 2 Power\n"); scanf("%d",&a); powerof2(a); 不,将count 重新初始化为0 是解决此问题的坏方法。移除全局变量,将bcount = 0定义为powerof2()中的局部变量。 并正确缩进你的代码。【参考方案10】:

下面的 C 语言程序将找出数字是否是 2 的幂,并找出数字是 2 的哪个幂。

#include<stdio.h>
void main(void)

    unsigned int a;
    unsigned int count=0
    unsigned int check=1;
    unsigned int position=0;
    unsigned int temp;
    //get value of a
    for(i=0;i<sizeof(int)*8;i++)//no of bits depend on size of integer on that machine
    
        temp = a&(check << i);
        if(temp)
        
            position = i;
            count++;
        
    
    if(count == 1)
    
        printf("%d is 2 to the power of %d",a,position);
    
    else
    
        printf("Not a power of 2");
    

还有其他方法可以做到这一点:- 如果一个数字是 2 的幂,那么二进制格式只会设置 1 位

例如 8 等价于 0x1000,从中减去 1,我们得到 0x0111。

以原始数字(0x1000)结束操作给出0。

如果是这样,数字是2的幂

    void IsPowerof2(int i)
    
    if(!((i-1)&1))
    
    printf("%d" is a power of 2, i);
    
    

另一种方式可以是这样的:-

如果我们取一个数字的补码,它是 2 的幂,

例如 8 的补码,即 0x1000 ,我们得到 0x0111 并将其加 1,我们得到 ​​p>

相同的数字,如果是这样,该数字是 2 的幂

    void IsPowerof2(int i)
    
    if(((~1+1)&i) == 1)
    
    printf("%d" is a power of 2,i):
    
                                                         

【讨论】:

请解释一下如何回答这个问题。 “这里有一些其他方法可以做同样的事情”并没有提供所要求的启示。

以上是关于这个按位运算如何检查 2 的幂?的主要内容,如果未能解决你的问题,请参考以下文章

php 使用按位运算符检查权限

这个按位与运算符如何屏蔽数字的低七位?

按位运算符探讨

按位运算的意外结果为啥 (1 | 1 & 2) 给出 1 而不是 2?

为啥这个逻辑/按位运算返回 1?

仅使用按位运算反转数字