关于c#:如何检查数字是否为2的幂

How to check if a number is a power of 2

今天我需要一个简单的算法来检查一个数字是否是2的幂。

算法需要:

  • 简单的
  • 修正任何ulong值。
  • 我想出了一个简单的算法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    private bool IsPowerOfTwo(ulong number)
    {
        if (number == 0)
            return false;

        for (ulong power = 1; power > 0; power = power << 1)
        {
            // This for loop used shifting for powers of 2, meaning
            // that the value will become 0 after the last shift
            // (from binary 1000...0000 to 0000...0000) then, the 'for'
            // loop will break out.

            if (power == number)
                return true;
            if (power > number)
                return false;
        }
        return false;
    }

    但后来我想,不如检查一下log2 x是否是一个精确的整数?但当我检查2^63+1时,由于四舍五入,Math.Log返回了63。所以我检查了2的幂63是否等于原始数,因为计算是在double中进行的,而不是精确的数:

    1
    2
    3
    4
    5
    6
    private bool IsPowerOfTwo_2(ulong number)
    {
        double log = Math.Log(number, 2);
        double pow = Math.Pow(2, Math.Round(log));
        return pow == number;
    }

    对于给定的错误值,返回true9223372036854775809

    有更好的算法吗?


    这个问题有一个简单的技巧:

    1
    2
    3
    4
    bool IsPowerOfTwo(ulong x)
    {
        return (x & (x - 1)) == 0;
    }

    注意,此函数将为0报告true,它不是2的幂。如果您想排除这一点,以下是方法:

    1
    2
    3
    4
    bool IsPowerOfTwo(ulong x)
    {
        return (x != 0) && ((x & (x - 1)) == 0);
    }

    解释

    首先,是msdn定义中的位二进制运算符:

    0

    现在让我们来看看这一切是如何发展的:

    函数返回布尔值(真/假),并接受一个无符号长型(在本例中为x)的传入参数。为了简单起见,我们假设有人传递了值4并像这样调用了函数:

    2

    现在,我们用4替换每一个出现的x:

    1
    return (4 != 0) && ((4 & (4-1)) == 0);

    我们已经知道了4!=0 evals为真,到目前为止还不错。但如何:

    1
    ((4 & (4-1)) == 0)

    当然,这可以解释为:

    1
    ((4 & 3) == 0)

    但究竟什么是4&3

    4的二进制表示为100,3的二进制表示为011(请记住,&;采用这些数字的二进制表示)。所以我们有:

    1
    2
    100 = 4
    011 = 3

    想象一下,这些值的叠加非常类似于初等加法。&运算符表示,如果两个值都等于1,则结果为1,否则为0。因此,1 & 1 = 11 & 0 = 00 & 0 = 00 & 1 = 0。所以我们来计算:

    1
    2
    3
    4
    100
    011
    ----
    000

    结果就是0。所以我们回头看看我们的退货声明现在翻译成了:

    1
    return (4 != 0) && ((4 & 3) == 0);

    现在翻译成:

    1
    return true && (0 == 0);
    1
    return true && true;

    我们都知道,true && true只是true,这表明在我们的例子中,4是2的幂。


    一些网站记录并解释了这一点和其他一些琐碎的黑客行为:

    • http://graphics.斯坦福.edu/~seander/bithacks.html(http://graphics.stanford.edu/~seander/bithacks.html DetermineifPowerof2)
    • http://bits.stephan-brumme.com网站/(http://bits.stephan-brumme.com/ispoweroftwo.html)

    还有他们的祖父,小亨利·沃伦的书《黑客的喜悦》:

    • http://www.hackersdelight.org网站/

    正如肖恩·安德森(SeanAnderson)的页面所解释的,((x & (x - 1)) == 0)的表达式错误地表明0是2的幂。他建议使用:

    1
    (!(x & (x - 1)) && x)

    纠正那个问题。


    return (i & -i) == i


    1
    2
    3
    4
    bool IsPowerOfTwo(ulong x)
    {
        return x > 0 && (x & (x - 1)) == 0;
    }


    我最近在http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/上写了一篇关于这个的文章。它包括位计数,如何正确使用对数,经典的"x&;&;!(X&;(X-1))"支票和其他。


    这里有一个简单的C++解决方案:

    1
    2
    3
    4
    bool IsPowerOfTwo( unsigned int i )
    {
        return std::bitset<32>(i).count() == 1;
    }


    在发布问题后,我想到了以下解决方案:

    我们需要检查二进制数字中是否有一个是1。所以我们只需将数字一次右移一位,如果它等于1,则返回true。如果在任何时候我们得到一个奇数((number & 1) == 1),我们就知道结果是false。这证明了(使用基准)对于(大)真值的速度略快于原始方法,对于假值或小值的速度则快得多。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    private static bool IsPowerOfTwo(ulong number)
    {
        while (number != 0)
        {
            if (number == 1)
                return true;

            if ((number & 1) == 1)
                // number is an odd number and not 1 - so it's not a power of two.
                return false;

            number = number >> 1;
        }
        return false;
    }

    当然,格雷格的解决方案要好得多。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        bool IsPowerOfTwo(int n)
        {
            if (n > 1)
            {
                while (n%2 == 0)
                {
                    n >>= 1;
                }
            }
            return n == 1;
        }

    这里有一个通用的算法,用来找出一个数是否是另一个数的幂。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        bool IsPowerOf(int n,int b)
        {
            if (n > 1)
            {
                while (n % b == 0)
                {
                    n /= b;
                }
            }
            return n == 1;
        }

    以下接受答案的附录可能对某些人有用:

    二的幂,当用二进制表示时,总是看起来像1,后面跟n个零,其中n大于或等于0。前任:

    1
    2
    3
    4
    5
    6
    7
    8
    Decimal  Binary
    1        1     (1 followed by 0 zero)
    2        10    (1 followed by 1 zero)
    4        100   (1 followed by 2 zeroes)
    8        1000  (1 followed by 3 zeroes)
    .        .
    .        .
    .        .

    等等。

    当我们从这些数字中减去1时,它们变为0,后面跟着n个数,然后n和上面一样。前任:

    1
    2
    3
    4
    5
    6
    7
    8
    Decimal    Binary
    1 - 1 = 0  0    (0 followed by 0 one)
    2 - 1 = 1  01   (0 followed by 1 one)
    4 - 1 = 3  011  (0 followed by 2 ones)
    8 - 1 = 7  0111 (0 followed by 3 ones)
    .          .
    .          .
    .          .

    等等。

    关键是

    0

    其中一个xx - 1的零对齐,所有x的零与x - 1的零对齐,导致按位和结果为0。这就是我们如何得到上面提到的单线答案是正确的。

    进一步增加了上述公认答案的美感。-

    因此,我们现在有一处财产可供我们使用:

    When we subtract 1 from any number, then in the binary representation
    the rightmost 1 will become 0 and all the zeroes before that rightmost
    1 will now become 1

    这个属性的一个令人敬畏的用途是找出给定数字的二进制表示中存在多少个1?对于给定的整数x,这样做的简短代码是:

    1
    2
    3
    byte count = 0;
    for ( ; x != 0; x &= (x - 1)) count++;
    Console.Write("Total ones in the binary representation of x = {0}", count);

    从上述概念可以证明的数字的另一个方面是"每个正数都可以表示为2的幂和吗?".

    是的,每个正数都可以表示为2的幂和。对于任何数字,取其二进制表示。例:取数字501

    1
    2
    3
    4
    The binary of 501 is 111110101

    Because  111110101 = 100000000 + 10000000 + 1000000 + 100000 + 1000 + 000 + 100 + 00 + 1
    we have  501       = 256       + 128      + 64      + 32     + 16   + 0   + 4   + 0  + 1


    1
    bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;


    找出给定的数字是否是2的幂。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <math.h>

    int main(void)
    {
        int n,logval,powval;
        printf("Enter a number to find whether it is s power of 2
    "
    );
        scanf("%d",&n);
        logval=log(n)/log(2);
        powval=pow(2,logval);

        if(powval==n)
            printf("The number is a power of 2");
        else
            printf("The number is not a power of 2");

        getch();
        return 0;
    }


    1
    2
    3
    4
    5
    6
    7
    bool isPowerOfTwo(int x_)
    {
      register int bitpos, bitpos2;
      asm ("bsrl %1,%0":"+r" (bitpos):"rm" (x_));
      asm ("bsfl %1,%0":"+r" (bitpos2):"rm" (x_));
      return bitpos > 0 && bitpos == bitpos2;
    }

    1
    2
    3
    4
    int isPowerOfTwo(unsigned int x)
    {
        return ((x != 0) && ((x & (~x + 1)) == x));
    }

    这真的很快。检查所有2^32个整数大约需要6分43秒。


    1
    return ((x != 0) && !(x & (x - 1)));

    如果x是2的幂,则其唯一的1位位于n的位置。这意味着x – 1的位置为0,n的位置为0。为了了解原因,回想一下二进制减法是如何工作的。当从x中减去1时,借位一直传播到位置n;位n变为0,所有低位变为1。现在,由于xx – 1没有1个相同的位,x & (x – 1)为0,!(x & (x – 1))为真。


    这里是我设计的另一种方法,在本例中使用|而不是&

    1
    2
    3
    4
    bool is_power_of_2(ulong x) {
        if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
        return (x > 0) && (x<<1 == (x|(x-1)) +1));
    }


    如果一个数字只包含一个设定位,那么它就是2的幂。我们可以使用这个属性和泛型函数countSetBits来确定一个数是否是2的幂。

    这是一个C++程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    int countSetBits(int n)
    {
            int c = 0;
            while(n)
            {
                    c += 1;
                    n  = n & (n-1);
            }
            return c;
    }

    bool isPowerOfTwo(int n)
    {        
            return (countSetBits(n)==1);
    }
    int main()
    {
        int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
        for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
            printf("Num:%d\tSet Bits:%d\t is power of two: %d
    "
    ,val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
        return 0;
    }

    我们不需要显式地检查0是否是2的幂,因为它也为0返回false。

    产量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Num:0   Set Bits:0   is power of two: 0
    Num:1   Set Bits:1   is power of two: 1
    Num:2   Set Bits:1   is power of two: 1
    Num:3   Set Bits:2   is power of two: 0
    Num:4   Set Bits:1   is power of two: 1
    Num:5   Set Bits:2   is power of two: 0
    Num:15  Set Bits:4   is power of two: 0
    Num:16  Set Bits:1   is power of two: 1
    Num:22  Set Bits:3   is power of two: 0
    Num:32  Set Bits:1   is power of two: 1
    Num:38  Set Bits:3   is power of two: 0
    Num:64  Set Bits:1   is power of two: 1
    Num:70  Set Bits:3   is power of two: 0


    例子

    2

    算法

  • 使用位掩码,将二进制中的变量NUM

  • IF R > 0 AND L > 0: Return FALSE

  • 否则,NUM变为非零

  • IF NUM = 1: Return TRUE

  • 否则,转到步骤1

  • 复杂性

    时间~O(log(d)),其中d是二进制位数。


    对于2的任何幂,以下也适用。

    n&(-n)=n

    注:n=0失败,需要检查这项工作的原因是:-n是n的2s补码。——n的每一个位都会相对于n翻转到n的最右边集合位的左边。对于2的幂,只有一个集合位。


    改进@user134548的答案,不使用位算术:

    1
    2
    3
    4
    5
    6
    7
    8
    public static bool IsPowerOfTwo(ulong n)
    {
        if (n % 2 != 0) return false;  // is odd (can't be power of 2)

        double exp = Math.Log(n, 2);
        if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
        return Math.Pow(2, exp) == n;
    }

    这对:

    1
    IsPowerOfTwo(9223372036854775809)


    如果数字为2的幂,如果Java的程序不是2的幂,则该程序返回"true",并返回"false"。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // To check if the given number is power of 2

    import java.util.Scanner;

    public class PowerOfTwo {
        int n;
        void solve() {
            while(true) {
    //          To eleminate the odd numbers
                if((n%2)!= 0){
                    System.out.println("false");
                    break;
                }
    //  Tracing the number back till 2
                n = n/2;
    //  2/2 gives one so condition should be 1
                if(n == 1) {
                    System.out.println("true");
                    break;
                }
            }
        }
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Scanner in = new Scanner(System.in);
            PowerOfTwo obj = new PowerOfTwo();
            obj.n = in.nextInt();
            obj.solve();
        }

    }

    OUTPUT :
    34
    false

    16
    true

    1
    2
    3
    4
    5
    private static bool IsPowerOfTwo(ulong x)
    {
        var l = Math.Log(x, 2);
        return (l == Math.Floor(l));
    }


    返回i>0&;&;(i^-i)==(-i<<1);

    还没有找到这样的答案。让它成为我的