我需要这样的功能:
// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true is_power_of_2(3) => false
bool is_power_of_2(int n);
谁能建议我该怎么写?您能告诉我一个好的网站,在哪里可以找到这种算法?
我需要这样的功能:
// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true is_power_of_2(3) => false
bool is_power_of_2(int n);
谁能建议我该怎么写?您能告诉我一个好的网站,在哪里可以找到这种算法?
Answers:
(n & (n - 1)) == 0
是最好的。但是,请注意,对于n = 0,它将错误地返回true,因此,如果可能的话,您将需要显式检查。
http://www.graphics.stanford.edu/~seander/bithacks.html包含大量的巧妙的比特稀疏算法,包括该算法。
(n>0 && ((n & (n-1)) == 0))
n && !(n & (n - 1))
作为答案状态内的链接。
n & !(n & (n - 1))
。注意按位AND &
(不是逻辑和&&
)。按位运算符不会实现短路,因此代码不会分支。在可能发生分支错误预测并且计算表达式的rhs(即!(n & (n - 1))
)便宜的情况下,这是首选方法。
!
是逻辑运算符,因此value !(n & (n - 1))
会是一个布尔值,您确定可以将按位AND运算符指定为布尔值和数字吗?如果是,那么看起来不错。
方法1:
用数字除以2来进行检查。
时间复杂度: O(log2n)。
方法2:
按位与,该数字及其前一个数字应等于零。
示例: Number = 8 Binary of 8:1 0 0 0 Binary of 7:0 1 1 1和两个数字的按位与是0 0 0 0 = 0。
时间复杂度: O(1)。
方法3:
将数字与前一个数字进行按位XOR运算应为两个数字的总和。
示例: Number = 8 Binary of 8:1 0 0 0 Binary of 7:0 1 1 1和两个数字的按位XOR为1 1 1 1 = 15。
时间复杂度: O(1)。
http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html
对于任何2的幂,以下条件也成立。
注意:该条件适用于n = 0,但不是2的幂。
之所以可行,原因是:
-n是n的2s补码。与n相比,-n将n的最右置位的每一位的左边翻转。对于2的幂,只有一个置1位。
在C ++ 20中std::ispow2
,如果您不需要自己实现它,则可以将其用于此目的:
#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));
如果使用GCC,这可能是最快的。它仅使用POPCNT cpu指令和一个比较。任何2的幂的二进制表示,始终只设置了一位,其他位始终为零。因此,我们用POPCNT来计算设置位的数量,如果等于1,则该数量为2的幂。我认为没有任何可能的更快方法。如果您一次了解它,它就非常简单:
if(1==__builtin_popcount(n))
i && !(i & (i - 1)))
,即使我确定要在gcc中启用本机程序集POPCNT指令,该测试在我的计算机上也要快10%左右。
在C ++中测试数字是否为2的幂的最简单方法是什么?
如果您具有带位操作说明的现代英特尔处理器,则可以执行以下操作。它省略了直接的C / C ++代码,因为其他人已经回答了它,但是如果BMI不可用或未启用,则需要它。
bool IsPowerOf2_32(uint32_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
return !!((x > 0) && _blsr_u32(x));
#endif
// Fallback to C/C++ code
}
bool IsPowerOf2_64(uint64_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
return !!((x > 0) && _blsr_u64(x));
#endif
// Fallback to C/C++ code
}
GCC,ICC和Clang信号BMI支持__BMI__
。当AVX2可用并启用时,在Visual Studio 2015及更高版本中的Microsoft编译器中可用。有关所需的标头,请参见SIMD内部函数的标头文件。
我平时守卫_blsr_u64
用_LP64_
的情况下,编译在i686。Clang需要一些解决方法,因为它使用了稍微不同的固有符号nam:
#if defined(__GNUC__) && defined(__BMI__)
# if defined(__clang__)
# ifndef _tzcnt_u32
# define _tzcnt_u32(x) __tzcnt_u32(x)
# endif
# ifndef _blsr_u32
# define _blsr_u32(x) __blsr_u32(x)
# endif
# ifdef __x86_64__
# ifndef _tzcnt_u64
# define _tzcnt_u64(x) __tzcnt_u64(x)
# endif
# ifndef _blsr_u64
# define _blsr_u64(x) __blsr_u64(x)
# endif
# endif // x86_64
# endif // Clang
#endif // GNUC and BMI
您能告诉我一个好的网站,在哪里可以找到这种算法?
该网站经常被引用:Bit Twiddling Hacks。
通过c ++是可能的
int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}
log2
,它肯定不是很快,并且证明它的工作原理不是那么容易解释(准确地说,您是否会被舍入错误所困扰?)。它也不必要地与混淆if..return..else..return
。折叠到return x==(double)y;
哪里有什么问题?它应该返回bool
anyayws。如果一个人真的愿意坚持,甚至IMO三元运算符也会更加清晰int
。
这是T-SQL(SQL Server)中的移位方法:
SELECT CASE WHEN @X>0 AND (@X) & (@X-1)=0 THEN 1 ELSE 0 END AS IsPowerOfTwo
它比四次对数快得多(第一个设置为获取小数结果,第二个设置为获取整数集并进行比较)