今天我需要一个简单的算法来检查数字是否是2的幂。
算法需要是:
- 简单
- 纠正任何
ulong
值。
我想出了这个简单的算法:
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;
}
但后来我想,如果检查log 2 x
是否正好是一个圆数呢? 但是当我检查2 ^ 63 + 1时,由于四舍五入, Math.Log
正好返回63。 所以我检查了功率63的2是否等于原始数字 - 它是,因为计算是用double
s进行的,而不是精确的数字:
private bool IsPowerOfTwo_2(ulong number)
{
double log = Math.Log(number, 2);
double pow = Math.Pow(2, Math.Round(log));
return pow == number;
}
对于给定的错误值,返回true
: 9223372036854775809
。
有更好的算法吗?
#1楼
return (i & -i) == i
#2楼
private static bool IsPowerOfTwo(ulong x)
{
var l = Math.Log(x, 2);
return (l == Math.Floor(l));
}
#3楼
int isPowerOfTwo(unsigned int x)
{
return ((x != 0) && ((x & (~x + 1)) == x));
}
这真的很快。 检查所有2 ^ 32个整数大约需要6分43秒。
#4楼
return ((x != 0) && !(x & (x - 1)));
如果x
是2的幂,则它的1位处于位置n
。 这意味着x – 1
位置为n
。 要了解原因,请回想一下二元减法是如何工作的。 当从x
减去1时,借位一直传播到位置n
; 位n
变为0,所有低位变为1.现在,由于x
与x – 1
没有共同的1位, x & (x – 1)
为0,并且!(x & (x – 1))
为真。
#5楼
这是我设计的另一种方法,在这种情况下使用|
而不是&
:
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));
}
#6楼
bool IsPowerOfTwo(ulong x)
{
return x > 0 && (x & (x - 1)) == 0;
}
#7楼
bool IsPowerOfTwo(int n)
{
if (n > 1)
{
while (n%2 == 0)
{
n >>= 1;
}
}
return n == 1;
}
这是一个通用算法,用于查明数字是否是另一个数字的幂。
bool IsPowerOf(int n,int b)
{
if (n > 1)
{
while (n % b == 0)
{
n /= b;
}
}
return n == 1;
}
#8楼
查找给定数字是否为2的幂。
#include <math.h>
int main(void)
{
int n,logval,powval;
printf("Enter a number to find whether it is s power of 2\n");
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;
}
#9楼
例
0000 0001 Yes
0001 0001 No
算法
使用位掩码,将
NUM
除以二进制变量IF R > 0 AND L > 0: Return FALSE
否则,
NUM
变为非零值IF NUM = 1: Return TRUE
否则,请转到步骤1
复杂
时间~ O(log(d))
其中d
是二进制数字的数量
#10楼
接受的答案的以下附录可能对某些人有用:
当以二进制表示时,2的幂将总是看起来像1,然后是n个零 ,其中n大于或等于0. Ex:
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再次与上面相同。 例如:
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)
. .
. .
. .
等等。
来到了症结所在
当我们对数字
x
进行按位运算时会发生什么,这是2的幂,x - 1
?
的一个x
被用的零对准x - 1
和的全部零x
与那些得到对准x - 1
,导致位与导致0。这就是我们如何有上述被提及的单行答案对。
进一步增加上面接受的答案之美 -
所以,我们现在拥有一处房产:
当我们从任何数字中减去1时,那么在二进制表示中,最右边的1将变为0,而最右边的1之前的所有零将变为1
这个属性的一个很棒的用法是找出 - 给定数字的二进制表示中有多少1? 对于给定的整数x
,执行此操作的简短代码是:
byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);
可以从上面解释的概念证明的数字的另一个方面是“每个正数可以表示为2的幂的总和吗?” 。
是的,每个正数都可以表示为2的幂的总和。对于任何数字,取其二进制表示。 例如:拿号码117
。
The binary representation of 117 is 1110101
Because 1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have 117 = 64 + 32 + 16 + 0 + 4 + 0 + 1
#11楼
这是一个简单的C ++解决方案:
bool IsPowerOfTwo( unsigned int i )
{
return std::bitset<32>(i).count() == 1;
}
#12楼
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
#13楼
对于任何2的幂,以下也适用。
N'( - N)==Ñ
注意:n = 0失败,因此需要检查它
这有效的原因是:
-n是n的2s补码。 与n相比,-n将n翻转的最右设置位左侧的每一位都设置为n。 对于2的幂,只有一个设置位。
#14楼
改进@ user134548的答案,无需位运算:
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;
}
这适用于:
IsPowerOfTwo(9223372036854775809)
#15楼
如果number是2的幂,则java中的该程序返回“true”,如果不是2的幂,则返回“false”
// 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
#16楼
return i> 0 &&(i ^ -i)==( - i << 1);
还没有找到这样的答案。 让它成为我的
#17楼
这个问题有一个简单的技巧:
bool IsPowerOfTwo(ulong x)
{
return (x & (x - 1)) == 0;
}
注意,此函数将为0
报告true
,这不是2
的幂。 如果你想排除它,这是如何:
bool IsPowerOfTwo(ulong x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
说明
首先是来自MSDN定义的按位二进制和运算符:
二进制和运算符是为整数类型和bool预定义的。 对于整数类型,&计算其操作数的逻辑按位AND。 对于bool操作数,&计算其操作数的逻辑AND; 也就是说,当且仅当它的两个操作数都为真时,结果才为真。
现在让我们来看看这一切是如何发挥作用的:
该函数返回boolean(true / false)并接受一个unsigned long类型的传入参数(在本例中为x)。 让我们为了简单起见假设某人已经传递了值4并且调用了这样的函数:
bool b = IsPowerOfTwo(4)
现在我们将每次出现的x替换为4:
return (4 != 0) && ((4 & (4-1)) == 0);
好吧,我们已经知道4!= 0 evals to true,到目前为止一直很好。 但是关于:
((4 & (4-1)) == 0)
这当然转化为:
((4 & 3) == 0)
但究竟什么是4&3
?
4的二进制表示为100,3的二进制表示为011(记住&取这些数字的二进制表示)。 所以我们有:
100 = 4
011 = 3
想象一下,这些价值就像基本的加法一样堆积起来。 &
运算符表示如果两个值都等于1,则结果为1,否则为0. So 1 & 1 = 1
1 & 0 = 0
0 & 0 = 0
0 & 1 = 0
。 所以我们做数学:
100
011
----
000
结果只是0.所以我们回过头来看看我们的返回语句现在转换为:
return (4 != 0) && ((4 & 3) == 0);
现在翻译为:
return true && (0 == 0);
return true && true;
我们都知道true && true
是true
,这表明对于我们的例子,4是2的幂。
#18楼
发布问题后,我想到了以下解决方案:
我们需要检查一个二进制数字是否只有一个。 所以我们一次只将数字右移一位,如果等于1则返回true
。如果在任何时候我们得到一个奇数( (number & 1) == 1
),我们知道结果是false
。 这证明(使用基准)比(大)真值的原始方法略快,对于假值或小值更快。
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;
}
当然,Greg的解决方案要好得多。
#19楼
一些记录和解释这个以及其他一些杂乱黑客的网站是:
- http://graphics.stanford.edu/~seander/bithacks.html
( http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 ) - http://bits.stephan-brumme.com/
( http://bits.stephan-brumme.com/isPowerOfTwo.html )
还有他们的祖父,小亨利·沃伦(Henry Warren,Jr。)写的“黑客的喜悦”一书 :
正如Sean Anderson的页面所解释的那样,表达式((x & (x - 1)) == 0)
错误地表明0是2的幂。他建议使用:
(!(x & (x - 1)) && x)
纠正这个问题。
#20楼
我最近在http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/上写了一篇关于此的文章。 它包括位计数,如何正确使用对数,经典的“x &&!(x&(x - 1))”检查等。
#21楼
如果数字仅包含1个设置位,则数字为2的幂。 我们可以使用此属性和泛型函数countSetBits
来查找数字是否为2的幂。
这是一个C ++程序:
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\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
return 0;
}
我们不需要明确检查0是2的幂,因为它也返回False为0。
OUTPUT
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
#22楼
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;
}