Hi, BeNuts!

BeNuts 程序官方博客

 

C# 中如何检查无符号长整形数是否为2的正整次方[终极版]

作者: uonun 发表时间: 2010-2-24 17:26:38
永久链接: http://udnz.com/Article/Is_That_Power_Of_Two.aspx
刚接触这个命题的时候,简单地想了想——很简单:
第一个方案:除2法。将它一直除以2,最后得到1则标识这个数是2的正整次方,得到一个小于1的小数则不是。

后来一想,这样的算法效率肯定不敢恭维,于是就有了下面的初步改进版:除2法的基础上进行奇偶判定。

private static bool IsPowerOfTwo_Obsolete(ulong value)
{
    double tmp = 0;
    while (value > 2)
    {
        /* 
         * 若 value 的值是2的正整数次方,则一直除以2的操作得到的数,必定仍然为偶数,直到为 1。
         * 反之,若 value 的值不是2的正整数次方,则除以2的操作必定在某一步的时候会产生一个奇数,假定这个奇数是N
         * 此时 N 除以2得到的浮点数必定和 N 除以2得到的整数值不相等。
         */ 
        tmp = Convert.ToDouble(value) / 2;
        if (tmp % 2 != 0)
        {
            return false;
        }
        else {
            value = value / 2;
        }
    }

    return value == 2;
}

其实写到这里,这个方法已经不错了。但后来继续挖掘信息,又一次改进了方法:进行二进制位比较,效率得到了大幅的提高:

//检查是否为2的正整数次方
private static bool IsPowerOfTwo_Obsolete2(ulong value)
{
    if (value > 1)
    {
        /* 
         * 针对每一个 ulong 的正整数,如果是2的正整数次方,则转换为二进制表示时一定有且仅有一个“1”存在。
         * 基于以上原理,则可以按位来比较。
         * 从低位到高位查询,遇到“1”后停止比较,所得到的数应当与原数相等,
         * 否则该数的二进制形式不止一个“1”位,即该数一定不是2的正整数次方。
         */
        ulong mask = 1ul;
        for (int count = 0;count < 64;count++)
        {
            //检查当前标识位是否为“0”
            if ((mask & value) == 0)
            {
                //当前位为“0”,则左移标识位,再次检查
                   mask <<= 1;
                continue;
            }

            /* 
             * 程序执行到此,表明当前标识位为“1”,停止检查。
             * 而此时的 mask 值正好应当与 value 相等,否则 value 就不是2的正整数次方。
             */
            return mask == value;
        }
    }
    return false;
}

感谢网友gbb21,他在此帖中提到使用如下语句,算是把这个执行效率提高到终极高度:

/// <summary>
/// 检查是否为2的正整数次方
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static bool IsPowerOfTwo(ulong value)
{
    if (value > 1)
    {
        return ((value - 1) & value) == 0;
    }
    return false;
}

到此为止,我想这个算法应该没多大提升空间了吧…

No comment for this post.

  • * 姓名(Name)
  • E-mail 或网站网址。支持基于 E-mail 的 Gravatar 头像。
  • * 验证码 看不清?点击换一个!