C 说明32位带符号整数是否为2的幂

C 说明32位带符号整数是否为2的幂,c,binary,logic,bit-manipulation,C,Binary,Logic,Bit Manipulation,我需要确定一个有符号的32位数字是否是2的幂。到目前为止,我知道要做的第一件事是检查它是否为负数,因为负数不能是2的幂。 然后我需要看看接下来的数字是否有效等等。。。所以我可以这样写: // Return 1 if x is a power of 2, and return 0 otherwise. int func(int x) { return ((x != 0) && ((x & (~x + 1)) == x)); } 但对于我的任务,我只能使用其中20

我需要确定一个有符号的32位数字是否是2的幂。到目前为止,我知道要做的第一件事是检查它是否为负数,因为负数不能是2的幂。 然后我需要看看接下来的数字是否有效等等。。。所以我可以这样写:

// Return 1 if x is a power of 2, and return 0 otherwise.
int func(int x)
{
     return ((x != 0) && ((x & (~x + 1)) == x));
}
但对于我的任务,我只能使用其中20个运算符:

! ~ & ^ | + << >>
!~&^ |+>
没有等式语句、循环、强制转换或语言构造


所以我试着转换相等部分,我知道!(a^b)与a==b是一样的,但我似乎不能完全理解它。有没有关于如何向允许的操作员隐瞒的想法?

蒂姆的评论让我感到羞愧。让我试着帮你自己找到答案


就位操作而言,
x
是2的幂是什么意思?这意味着只有一位设置为1。我们怎么能做这样一个把戏,把那个位变成0,其他的可能变成1?那么&将给出0?用单一的表达?如果你发现了,你就赢了。

想想这个。。。任何2减1的幂都是0加1的字符串。您可以通过
x+~0
实现负1。想想1的字符串从什么地方开始,与2的幂次中的单个1相关。

试试以下想法:

  • ~!!x+1给出了一个掩码:如果
    x==0,则为0;如果
    x,则为-1=0
  • (x&(~x+1))^x
    如果
    x
    最多设置了1位,则为0,否则为非零,除非
    ~x
    INT\u MIN
    ,在这种情况下,结果未定义。。。为了避免这种情况,您可以使用位移位将其拆分为多个部分,但我认为您将超过操作限制
  • 您还需要检查符号位,因为负值不是二的幂

顺便说一句,听起来你的指导老师不知道C中的有符号溢出是UB。他应该为无符号整数编写这些问题。即使您希望在语义上将值视为有符号的值,也需要使用无符号算术来执行这样有意义的位运算。

在C中使用位运算符来解决一些问题是有趣而有效的。在这个问题上,我们需要处理两个检查:

int ispower2(int x)
{

    int ispositive= ! ( (x>>31) ^ 0) & !!(x^0);         
    int temp= !((x & ~x+1) ^ x);
    return temp & ispositive;

}
  • 标志检查。如果为负数,则返回0;否则返回1

    !!(x>>31&ox1)和!(!x)

    /*此操作提取x中的符号位。但是,本例中的>>将是算术的。这意味着在最后一位(LSB)之前将有所有1。对于负int,它是oxffffff(-);否则,OxFFFFFE(+)。和ox1操作将>>更正为ox1(-)或ox0(+)。合乎逻辑!将ox1(-)和ox0(+)分别转换为0或1。这个(!x)确保0不是电源(2)*/

  • 电源(2)检查。如果是,返回1;否则为0

    !!(x&(~x+ox1)^x)

    /*此操作执行iPower(2)检查。x&(~x+ox1)返回x,当且仅当x是幂(2)。例如:x=ox2和~x+ox1=oxfffffe。x&(~x+ox1)=ox2;如果x=ox5和~x+ox1=oxfffffb。x&(~x+ox1)=ox1。因此,ox2^ox2=0;但是ox5^ox1=ox4。这个op将0和其他值分别转换为1和0*/


  • 最后一次和操作。1到2次检查将生成iPower(2)功能的结果

    首先,在您的解决方案中

    return ((x > 0) && ((x & (~x + 1)) == x));
    
    因为负数不能是2的幂。 根据您的要求,我们需要将“>”、“&&”、“==”转换为允许的运算符

    首先考虑“>”,一个大于0的整数,其符号位为1,而不是0;所以我们考虑

    ~(x >> 31) & (x & ~0)
    
    如果x为非正数,则上面的表达式将返回一个非零数。请注意~0=-1,即0x11111111。我们使用x&~0来检查这个整数在每个数字上是否都是0

    其次,我们考虑“& &”。这非常简单——我们只需要得到0x01&0x01就可以返回1。因此,这里我们需要在第一个答案前面添加(!!),如果它返回一个非零数,则将其更改为0x01

    最后,我们考虑“==”。为了测试A和B的公平性,我们只需要

    !(A ^ B)
    
    所以最后我们有

    return (!!(~(x >> 31) & (x & ~0))) & (!((x&(~x+1)) ^ x))
    

    这似乎是个家庭作业问题。请不要简单地复制和粘贴。我的答案有点尴尬,可能会有所改进。

    如果有人能找到一种方法来回答这个问题而不只是给出答案,那将是一件有趣的事情。在这种情况下,一个非常有用的技巧是
    !!x
    。这将使数字正常化,因此0变为0,而非-0变为1。它甚至是高效的(编译器对此进行了优化)。我总是遇到麻烦!!如果x=2,那么!x=1,然后!!x=0。如果x=0!x=0和!!x=1?我是否可以为“不称职的CS讲师x处理-
    !~&^+
    问题”打开一个新的stackexchange站点提案?这已经到了我们有足够的时间来处理整个站点的地步……我认为如果讲师也理解C,这些问题会很好,但按照他/她所说的方式,这些问题在C中是无法解决的,并且期望的“解决方案”充满了未定义的行为(这可以通过切换到无符号算术来解决)。我还认为很不幸,班上的一个学生发现/知道堆栈溢出,并告诉全班同学来这里为他们完成作业……你觉得他们怎么样?老师通常都是没有行业经验的人,这总是让我感到痛苦。他们唯一的经验就是玩弄,我真的不明白。作为一个在学术界工作过的人(承认是数学而不是计算机科学),我总是希望学术工作中对精确定义的严谨和关注。然而,我们一次又一次地看到,在CS作业中,讲师显然不关心他们正在使用的语言的精确定义和规格……这个问题意味着
    1@Peter,有符号32位数字为否
    1@Peter:如果你问的是整数溢出,这并不罕见。欢迎来到SO,谢谢你