判断一个数是不是2的幂

时间:2022-04-25
本文章向大家介绍判断一个数是不是2的幂,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

我们经常会遇到这样一个问题,就是判断某个数据是否为2的n次方(1,2,4,8,16...)。例如如果用户输入的不是2^n,则要求用户重新输入。为了说明这种判断算法,我首先构造一个测试程序,代码如下:

#include <stdio.h>

#include <time.h>

 

int main()

{

    long unsigned int i;

    clock_t start,end;

    start = clock();

    for(i=1;i<100000000;i++)

    {

        if(is2Power(i))

        {

            printf("%ldn",i);

        }

    }

    end =clock();

    printf("The total time is: %lf",((double)(end-start))/CLOCKS_PER_SEC);

    return 0;

}

一般人很容易想到下面的算法:

int is2Power(long unsigned int num)

{

    long unsigned int i;

    for(i=1;i<=num;i*=2)

    {

        if(i == num)

        {

             return 1;

        }

    }

    return 0;

}

该算法很容易理解,但是效率不算特别高,在我的机器上的测试结果为:The total time is: 28.566000,有人提出,其中的i*=2,可以用i<<=1来替换,效率应该会高一些,我们可以尝试一下:

int is2Power(long unsigned int num)

{

    long unsigned int i;

    for(i=1;i<=num;i<<=1)

    {

        if(i == num)

        {

             return 1;

        }

    }

    return 0;

}

在我的机器上的测试结果为:The total time is: 27.821000,我们发现仅仅提高了不到一秒,基本可以忽略不计。又有人提出,我们可以采取另一种思路,让i从num开始每次除2来判断,如果余数不为0立即返回,这样能会快判断出那些不符合条件的值,这样便能加快判断速度。

int is2Power(long unsigned int num)

{

    long unsigned int i;

    for(i=num;i>=1;i/=2)

    {

        if(i==1)

            return 1;

        else if(i%2 != 0)

        {

             return 0;

        }

    }

    return 1;

}

这种算法在我的机器上的测试结果为:The total time is: 3.958000,可以看出效率提高了近8倍。这时又有大神提出,由于2的n次方的数二进制表示是第1位为1,其余为0,而x-1(假如x为2的n次方)得到的数的二进制表示恰恰是第1位为0,其余为1,两者相与,得到的结果就为0,否则结果肯定不为0。于是诞生了如下算法:

int is2Power(long unsigned int num)

{

    return ((num & (num-1))==0)?1:0;

}

简单的有点吓人,而且效率也很高,在我的机器上的测试结果为:The total time is: 1.484000,当然也有一个类似的算法,原理类似:

int is2Power(long unsigned int num)

{

    return ((num & (~num+1))==num)?1:0;

}

这种算法在我的机器上的测试结果为:The total time is: 1.503000

很简单的问题,只要我们仔细研究一下还是有不少收获的。

注:文中的算法仅说明了相对的效率问题,鲁棒性并没有测试,如果你在实际情况中使用,需要注意一下边界值和反常输入情况。