整理了下, 有以下这么多。

me以前是做测试的, 现在乱七八糟什么活都做,一直没好好学算法, 没法写出很好的算法来娱乐大家。

me算法很弱的。

但是me挑刺的习惯倒是没有改正。  所以很high的开始分析别人的代码。

让我们分析一下大家回复的几种典型代码(运行正确的咱们就不分析了):

 

1 宏定义。 

 

#define ISPOW2(x) (x) & (x-1) ? false : true

这个我刚写了一篇文章来证明他存在一点小的瑕疵。 那就是当x为0的时候,

 

我们知道0不是2的n次方, 简单的说就是LOG(2,0) 是没有值的。

而对于这个判断, 0和-1进行按位与, 必然是0. 居然可以让判断通过。

一个反例否定一种算法, 这不算过分。

当然, 修饰一下, 这个算法还是挺不错的。 至少我自己看的时候觉得挺震惊。 毕竟是第一次见到。

=。=

不要嘲笑我见识少。。。我真的是第一次。

2   7楼的修正版

 

    public static bool floor_7(int num)
    {
        
if (num <= 1)
        {
            
return false;
        }
        
else
        {
            
return ((num & (num - 1)) == 0? true : false;
        }
    }

 

 7楼似乎自己就意识到了这个问题, 就进行了判断。

遗憾的是, 他多判断了一个1. 我们知道, 1是2的0次方。 1应该是符合要求的。

 

3  8楼的修正版

 

    public bool floor_8(int n)
    {
        
if (n < 0)
            
throw new InvalidOperationException();
        
if (n < 2)
            
return false;

        
return n & (n - 1== 0;
    }

 8楼还意识到了负数的问题。 可惜他和7楼存在相同的问题。不过这只是小错误。

 4 22楼的对数算法

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

 

22楼的对数算法比较有趣, 可惜, 浮点误差毕竟不是个容易避开的问题。

因为浮点数不能直接比较, 所以用了一个0.00001来做尺度。

这就存在了一个问题:当x很大的时候呢?

我找了一个变态的数字来测试:

 

0x10000001

 

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

 =。=

(我是不是有点心理变态啊。。 )

又是一个反例推翻一个算法的思路。

5 37楼的算法。

    public static bool floor_37(int num)
    {
        
double result = Math.Log(num, 2);
        
if (result.ToString().IndexOf(".">= 0)
        {
            
return false;
        }
        
else
        {
            
return true;
        }
    }

 

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

 

 所以总结了下, (x)&(x-1)的算法还没有被证明, 不知道除了0还有没有别的反例。

因为毕竟这个算式没有严密的证明过程, 参见我的另一篇文章:

 

 

因此我觉得, 最保险的还是位运算, 看多少个1, 来的最实在。

当然这里存在一个负数的问题。第一位是1, 剩下全是0的问题。 不过有一位聪明的回复者提供了一个很强大的方法来避开负数的用例:

他给参数定的类型是uint!

好吧你赢了。

 

刚看到一个最牛的:

 

public bool is_(int num)
{
    
switch (num)
    {
        
case 0x0002:
        
case 0x0004:
        
case 0x0008:
        
case 0x0010:
        
case 0x0020:
        
case 0x0040:
        
case 0x0080:
        
case 0x0100:
        
case 0x0200:
        
case 0x0400:
        
case 0x0800:
        
case 0x1000:
        
case 0x2000:
        
case 0x4000:
        
case 0x8000:
            
return true;
        
default:
            
return false;
    }
}

 

 如果再加个0x0001, 我觉得就完美了。。。

 当然还要继续写下去, 确实这个满累人的。