如何判断一个数是不是2的n次幂

本文详细介绍了通过位运算判断一个整数是否为2的幂次方的方法,并对比了不同算法的效率与准确性。包括经典算法、改进算法、对数算法及修正后的版本,特别强调了二进制表示和按位与运算在解决此问题上的优势。
题目:给定一个整数num,判断这个整数是否是2的N次方。比如,2,4,8是2的那次方,6,10不是2的N次方。

请看下面的程序:

public static bool Check1(int num)


{
    int i = 1;
    while (true)
    {
        if (i > num)
            return false;
        if (i == num)
            return true;
        i = i * 2;
    }
}
不断的循环num%2,如果不等于0,return false,如果等于0,num=num/2,一直做到num=1

public static bool Check2(int num)
{
    if (num == 1)
        return true;
    else
    {
        do
        {
            if (num % 2 == 0)
                num = num / 2;
            else
                return false;
        }
        while (num != 1);
        return true;
    }
}
其实这两种算法的思路都是相同的,但是第二种相对第一种更高效写,因为如果不是2的N次方,可以少循环很多次!

由于2的N次方的数二进制表示是第1位为1,其余为0,而x-1(假如x为2的N次方)得到的数的二进制表示恰恰是第1位为0,其余为1,两者相与,得到的结果就为0,否则结果肯定不为0。


public static boolean getResult(int num)
{
    if (num <= 1)
    {
        return false;
    }
    else
    {
        return ((num & (num - 1)) == 0) ? true : false;
    }
}
public static void main(String[] args) {
    System.out.println(getResult(32));
}
上面的程序多判断了一个1. 我们知道, 1是2的0次方。 1应该是符合要求的。下面修正:


public static bool floor_7(int num)
{
    if (num < 1)
    {
        return false;
    }
    else
    {
        return ((num & (num - 1)) == 0) ? true : false;
    }
}
如果一个数是2的整数次幂,那么表示为二进制的时候会是这样:010000....


除了2的零次方,即1之外,这个数减一会得到:001111....


换言之得到一个前面全是0后面全是1的数,把这个数和原数做个按位与,得到:000000.....


换言之,如果一个数n,其不为1,且n-1 & n = 0,那么n就是一个2的整数次幂。因为只要他表达为二进制时存在两个1,就不会满足这条规律。所以最简判断方法就是:
if ( n < 0 )
throw new InvalidOperationException();
if ( n < 2 )
return false;
return n & ( n - 1 ) == 0
修正之后:
public bool floor_8(int n)
{
    if (n < 0)
        throw new InvalidOperationException();
    if (n < 2)
        return false;
    return n & (n - 1) == 0;
}
对数算法:

bool foo(int x)
{
    float ret = log(x)/log(2);
    return abs((int) ret - ret) <= 0.00001;
}
修正后:

public bool floor_22(int x)
{
    float ret = log(x) / log(2);
    return abs((int)ret - ret) <= 0.00001;

}
对数算法比较有趣, 可惜, 浮点误差毕竟不是个容易避开的问题。因为浮点数不能直接比较, 所以用了一个0.00001来做尺度。这就存在了一个问题:当x很大的时候呢?我找了一个变态的数字来测试:0x10000001

结果是true。因为结果的小数部分实在是太小了。


static void Main(string[] args)
{
    int i = int.Parse(Console.ReadLine());
    Console.WriteLine(IsCheck(i));
}
public static bool IsCheck(int num)
{
    double result = Math.Log(num, 2);
    if (result.ToString().IndexOf(".") >= 0)
    {
        return false;
    }
    else
    {
        return true;
    }


}
相同的问题。 只要使用了LOG, 就无法避免掉浮点数丢精度的问题。 这是没办法的事情。


public static bool floor_37(int num)
{
    double result = Math.Log(num, 2);
    if (result.ToString().IndexOf(".") >= 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
所以总结了下, (x)&(x-1)的算法还没有被证明, 不知道除了0还有没有别的反例。因为毕竟这个算式没有严密的证明过程。


因此我觉得, 最保险的还是位运算, 看多少个1, 来的最实在。当然这里存在一个负数的问题。第一位是1, 剩下全是0的问题。 不过有一位聪明的回复者提供了一个很强大的方法来避开负数的用例:他给参数定的类型是uint!

     推荐:http://www.nowamagic.net/librarys/veda/detail/1031

<think>嗯,用户想了解用C语言判断一个是否2的幂的方法。首先,我需要回忆一下相关的知识。记得2的幂的在二进制表示中只有一位是1,其余都是0,比如2^3是8,二进制是1000。那如何利用这个特性呢? 根据引用[2]和[3],可以使用位运算来判断。比如,当一个n是2的幂时,n & (n - 1)的结果应该是0,因为减1后,原来的1变成了0,后面的0全变成1,按位与就会得到0。但还要注意,如果n本身是0或者负,需要先排除,所以函里要先检查num <= 0的情况。 然后,用户可能需要具体的代码示例。引用[1]中的代码展示了这个方法的实现,包括主函里的输入输出部分。代码逻辑清晰,先处理非正的情况,再用位运算判断。 另外,用户可能想知道这种方法的时间复杂度,应该是O(1),因为只进行了一次位运算操作。而其他方法,比如循环除以2直到余不为0,虽然可行,但效率较低,时间复杂度是O(log n)。 可能还需要解释为什么这种方法有效。例如,对于n=8(1000),n-1=7(0111),按位与后为0;而n=6(0110),n-1=5(0101),按位与后为0100,不等于0。因此,只有当n是2的幂时,这个条件成立。 最后,用户可能对应用场景或进一步优化感兴趣,比如如何计算是2的多少次方,或者处理更大的值范围。但根据问题,主要关注判断是否2的幂即可。需要确保代码正确,比如测试几个例子,如n=1、2、4、8以及非2的幂的如3、5、6等,验证结果是否正确。</think>### 用C语言判断一个是否2的幂的方法 #### 方法原理 2的幂次方在二进制表示中具有以下特性:**仅有一个位是1,其余位均为0**。例如: - $2^3 = 8$ 对应二进制为 $1000$ - $2^5 = 32$ 对应二进制为 $100000$ 利用这一特性,可以通过**位运算**快速判断。具体步骤为: 1. **排除非正整**:若小于等于0,则不可能是2的幂。 2. **位运算验证**:若 $n$ 是2的幂,则 $n \& (n - 1) = 0$。例如: - $n=8$(二进制 $1000$),$n-1=7$(二进制 $0111$),则 $1000 \& 0111 = 0000$。 - 若 $n$ 不是2的幂(如 $n=6$,二进制 $0110$),则 $n \& (n-1) = 0110 \& 0101 = 0100 \neq 0$[^2]。 #### 代码实现 ```c #include <stdio.h> int isPowerOfTwo(int num) { if (num <= 0) { return 0; // 排除非正整 } return (num & (num - 1)) == 0; } int main() { int number; printf("Enter a number: "); scanf("%d", &number); if (isPowerOfTwo(number)) { printf("%d is a power of 2.", number); } else { printf("%d is not a power of 2.", number); } return 0; } ``` #### 代码解释 1. **函 `isPowerOfTwo`**: - 输入参数为整 `num`。 - 若 `num ≤ 0`,直接返回0(非2的幂)。 - 通过 `num & (num - 1) == 0` 判断是否满足2的幂的特性。 2. **主函 `main`**: - 读取用户输入的整。 - 调用 `isPowerOfTwo` 函并输出结果。 #### 时间复杂度 该方法仅需**一次位运算操作**,时间复杂度为 $O(1)$,效率远高于传统循环除法(时间复杂度 $O(\log n)$)[^2]。 #### 注意事项 - 若需判断更大的值范围(如超过 `int` 类型范围),可使用 `unsigned int`。 - 若需进一步计算2的幂次方值(如确定是2的多少次方),可通过**二进制中1的位置**推导[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值