How to check if a number is a power of 2
今天我需要一个简单的算法来检查一个数字是否是2的幂。
算法需要:
我想出了一个简单的算法:
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; } |
但后来我想,不如检查一下
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; } |
对于给定的错误值,返回
有更好的算法吗?
这个问题有一个简单的技巧:
1 2 3 4 | bool IsPowerOfTwo(ulong x) { return (x & (x - 1)) == 0; } |
注意,此函数将为
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的二进制表示为100,3的二进制表示为011(请记住,&;采用这些数字的二进制表示)。所以我们有:
1 2 | 100 = 4 011 = 3 |
想象一下,这些值的叠加非常类似于初等加法。
1 2 3 4 | 100 011 ---- 000 |
结果就是0。所以我们回头看看我们的退货声明现在翻译成了:
1 | return (4 != 0) && ((4 & 3) == 0); |
现在翻译成:
1 | return true && (0 == 0); |
1 | return true && true; |
我们都知道,
一些网站记录并解释了这一点和其他一些琐碎的黑客行为:
- 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)的页面所解释的,
1 | (!(x & (x - 1)) && x) |
纠正那个问题。
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,则返回
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 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其中一个
因此,我们现在有一处财产可供我们使用:
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?对于给定的整数
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的幂和。对于任何数字,取其二进制表示。例:取数字
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))); |
如果
这里是我设计的另一种方法,在本例中使用
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的幂。我们可以使用这个属性和泛型函数
这是一个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算法
使用位掩码,将二进制中的变量
否则,
否则,转到步骤1
复杂性
时间~
对于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);
还没有找到这样的答案。让它成为我的