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

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, 我觉得就完美了。。。

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