怎么判断一个数是不是2的N次方

来源:互联网 发布:java插件下载win7 编辑:程序博客网 时间:2024/04/27 14:15

题目:给定一个整数num,判断这个整数是否是2的N次方。比如,2,4,8是2的那次方,6,10不是2的N次方。

请看下面的程序:

 
01public static bool Check1(intnum)
02{
03    inti =1;
04    while(true)
05    {
06        if(i > num)
07            returnfalse;
08        if(i == num)
09            returntrue;
10        i = i *2;
11    }
12}

不断的循环num%2,如果不等于0,return false,如果等于0,num=num/2,一直做到num=1

 
01public static bool Check2(intnum)
02{
03    if(num ==1)
04        returntrue;
05    else
06    {
07        do
08        {
09            if(num %2== 0)
10                num = num /2;
11            else
12                returnfalse;
13        }
14        while(num !=1);
15        returntrue;
16    }
17}

其实这两种算法的思路都是相同的,但是第二种相对第一种更高效写,因为如果不是2的N次方,可以少循环很多次!

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

01public static boolean getResult(int num)
02{
03    if(num <=1)
04    {
05        returnfalse;
06    }
07    else
08    {
09        return((num & (num -1)) ==0) ?true: false;
10    }
11}
12public static void main(String[] args) {
13    System.out.println(getResult(32));
14}

上面的程序多判断了一个1. 我们知道, 1是2的0次方。 1应该是符合要求的。下面修正:

01public static bool floor_7(int num)
02{
03    if(num <= 1)
04    {
05        returnfalse;
06    }
07    else
08    {
09        return((num & (num - 1)) == 0) ? true : false;
10    }
11}

如果一个数是2的整数次幂,那么表示为二进制的时候会是这样:010000....

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

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

换言之,如果一个数n,其不为1,且n-1 & n = 0,那么n就是一个2的整数次幂。因为只要他表达为二进制时存在两个1,就不会满足这条规律。所以最简判断方法就是:

 
1if ( n < 0 )
2throw new InvalidOperationException();
3if ( n < 2 )
4return false;
5return n & ( n - 1 ) == 0

修正之后:

 
1public bool floor_8(int n)
2{
3    if(n < 0)
4        thrownewInvalidOperationException();
5    if(n < 2)
6        returnfalse;
7    returnn & (n - 1) == 0;
8}

对数算法:

 
1bool foo(int x)
2{
3    float ret = log(x)/log(2);
4    returnabs((int) ret - ret) <= 0.00001;
5}

修正后:

 
1public bool floor_22(int x)
2{
3    float ret = log(x) / log(2);
4    returnabs((int)ret - ret) <= 0.00001;
5}

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

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

 
01static void Main(string[] args)
02{
03    inti =int.Parse(Console.ReadLine());
04    Console.WriteLine(IsCheck(i));
05}
06public static bool IsCheck(intnum)
07{
08    doubleresult = Math.Log(num,2);
09    if(result.ToString().IndexOf(".") >=0)
10    {
11        returnfalse;
12    }
13    else
14    {
15        returntrue;
16    }
17}

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

 
01public static bool floor_37(int num)
02{
03    double result = Math.Log(num, 2);
04    if(result.ToString().IndexOf(".") >= 0)
05    {
06        returnfalse;
07    }
08    else
09    {
10        returntrue;
11    }
12}

所以总结了下, (x)&(x-1)的算法还没有被证明, 不知道除了0还有没有别的反例。因为毕竟这个算式没有严密的证明过程

0 0
原创粉丝点击