n & (n - 1) == 0 且 n > 0 能判断2的幂,因2的幂二进制仅一个1,n-1将其右侧全置1,与运算得0;但需排除n≤0及溢出情况,故必须加正数检查。

为什么 n & (n - 1) 能判断 2 的幂
因为 2 的幂在二进制下只有一个比特为 1,比如 1(1)、2(10)、4(100)、8(1000)。而 n - 1 会把那个唯一 1 右侧所有位变成 1,高位全 0。两者按位与结果必为 0。
例如:8 是 1000,7 是 0111,8 & 7 == 0。
但必须排除 n 的情况——负数和 0 不是 2 的幂,且 <code>0 & (0 - 1) 会误判(0 & (-1) 在补码下非零)。
-
n > 0是前提,不可省略 - 该操作是常数时间、无分支、CPU 友好,比循环除 2 或 log2 快得多
- 对
int、long long都适用,但要注意符号位:仅用于无符号或已确认为正的有符号整数
如何写一个安全可靠的判断函数
直接用 (n > 0) && ((n & (n - 1)) == 0) 即可。这是最常用也最稳妥的写法。
示例:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
- 不要写成
!n & (n - 1)—— 逻辑非优先级高于按位与,实际等价于!(n & (n - 1)),但漏了正数检查 - 不要对
unsigned int省略n > 0—— 无符号类型下n > 0等价于n != 0,仍需显式写,语义清晰 - 编译器通常能将该表达式优化为单条指令(如 x86 的
test+jz),无需手动内联汇编
边界情况与容易踩的坑
常见误判点集中在 0、1 和溢出边缘值上。
-
isPowerOfTwo(0)必须返回false;若只用n & (n - 1) == 0,0会返回true(因为0 & 0xffffffff == 0) -
isPowerOfTwo(1)正确返回true(1 & 0 == 0,且1 > 0) - 对
INT_MIN(如 -2147483648)调用会触发未定义行为——n - 1溢出,所以务必先检查符号或使用无符号类型 - 若输入可能为
unsigned long long,确保用对应字长的字面量(如1ULL),避免隐式截断
扩展:判断是否为 2 的非零次幂(排除 2⁰ = 1)
有些场景需要排除 1,比如内存页大小校验要求至少 2KB。这时不能只改条件,而要额外限制。
- 写成
n > 1 && (n & (n - 1)) == 0 - 注意:此时
isPowerOfTwo(2)返回true,isPowerOfTwo(1)返回false - 别试图用
n >> 1替代n > 1——对 1 做右移仍是 0,但语义模糊且不等价
真正难的不是公式本身,而是记住它只对正整数有效,以及每次调用前心里默念一遍“n 大于 0 吗”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










