<p>n & (n - 1) == 0 且 n > 0 可判断正整数是否为2的幂,因2的幂二进制仅一个1,n-1使该位变0、右侧全变1,按位与得0;需显式排除非正数,推荐写法为 return n > 0 && (n & (n - 1)) == 0。</p>

为什么 n & (n - 1) 能判断2的幂
一个正整数是2的幂,意味着它的二进制表示里只有一个 1,其余全是 0,比如 8 是 1000。这时 n - 1 会把最低位的 1 变成 0,右边所有 0 全变成 1(如 8-1=7 → 0111)。n & (n - 1) 的结果就一定是 0。
但要注意:这个技巧只对正整数有效,0 和负数必须单独排除。
-
0:0 & (0 - 1)是0 & (-1),在补码下结果非零,误判为“不是2的幂”——其实0本来就不是2的幂,但逻辑上得显式排除 - 负数:C++中负数的位运算行为依赖实现,且数学上负数不可能是2的幂,直接拒绝
标准写法:处理边界情况
最稳妥的判断逻辑是:
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}关键点:
立即学习“C++免费学习笔记(深入)”;
-
n > 0必须放在前面,利用短路求值避免对0或负数计算n - 1 - 不要写成
(n & (n - 1)) == 0 && n != 0——n == 0时n - 1是-1,0 & (-1)在大多数平台是0,看似能蒙混过关,但这是靠补码细节“碰巧”,不可靠 - 如果输入可能是
unsigned int,仍需n != 0,因为0u - 1u会回绕成极大值,n & (n - 1)不为0,但显式写n != 0更直白
用 std::popcount(C++20)是否更清晰
C++20 引入了 std::popcount,它返回整数二进制中 1 的个数。判断2的幂就变成:
#include <bit>
bool isPowerOfTwo(unsigned int n) {
return n != 0 && std::popcount(n) == 1;
}优点是语义清晰、无需记忆位运算技巧;缺点是:
- 仅支持无符号整数类型,
int需先转成unsigned(否则负数行为未定义) - 编译器可能将
std::popcount编译为单条 CPU 指令(如 x86 的POPCNT),性能不输位运算;但若目标平台不支持,会退化为软件实现,略慢 - 需要 C++20 且开启对应标准支持(如
-std=c++20)
容易忽略的整型溢出陷阱
如果用 int 存储大数,比如判断 INT_MAX 是否为2的幂,会出问题:
-
INT_MAX是2147483647,不是2的幂,但INT_MAX + 1溢出为INT_MIN,而INT_MIN是-2147483648,恰好等于-2^31—— 这是2的幂的负数形式,但题目通常只要求正整数幂 - 所以函数签名用
int本身已隐含范围限制;若业务需要处理接近边界的值,建议用long long或unsigned long long,并配合对应位宽的判断逻辑 - 例如对
unsigned long long n,依然可用n && !(n & (n - 1)),但要确保头文件和编译器支持 64 位整型的原子操作
位运算判断本身很快,但真正容易出错的永远是边界和类型选择,而不是公式本身。


















