n & (n - 1) == 0 能判断2的幂,因为2的幂二进制仅一个1,n-1将其右侧全置1,按位与得0;但必须先确保n > 0,否则0和负数会误判。

为什么 n & (n - 1) 能判断 2 的幂
因为 2 的幂在二进制中只有一位是 1,其余全是 0,比如 1(1)、2(10)、4(100)、8(1000)。而 n - 1 会把那个唯一的 1 变成 0,并把它右边所有 0 全变成 1。所以 n & (n - 1) 结果必为 0 —— 这是本质特征。
但要注意:这个技巧只对正整数有效,0 和负数必须提前排除。
常见错误现象:isPowerOfTwo(0) 返回 true,或 isPowerOfTwo(-4) 返回 true(取决于编译器对负数右移/补码的处理,但逻辑上绝对错误)。
- 必须先检查
n > 0 -
n类型推荐用无符号整数(如unsigned int),避免符号位干扰 - 对
int类型,n == 1是合法的 2 的幂,n & (n - 1)在n == 1时计算为1 & 0 == 0,结果正确
n & (n - 1) == 0 的边界情况怎么处理
最常被忽略的是 0:因为 0 & (0 - 1) 实际是 0 & 0xFFFFFFFF(补码下),结果为 0,误判为真。负数同理,比如 -2 的二进制(以 32 位为例)是 0xFFFFFFFE,-2 & -3 得 0xFFFFFFFE ≠ 0,看似安全,但语义完全错误 —— 负数不可能是 2 的幂。
所以判断逻辑必须是:
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
如果输入类型是 unsigned int,可省略符号检查,但仍需排除 0:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
bool isPowerOfTwo(unsigned int n) {
return n != 0 && (n & (n - 1)) == 0;
}
和除法循环法比,位运算快在哪
除法循环(不断除以 2 直到余数非 0 或等于 1)时间复杂度是 O(log n),且涉及取模、除法指令,在旧 CPU 上开销明显;而 n & (n - 1) 是单条位操作指令,现代 CPU 一个周期就能完成,常数级延迟。
但要注意:编译器对简单循环可能做优化(比如识别出除 2 等价于右移),实际性能差距在小数据上不明显;真正拉开差距的是高频调用场景(如哈希表容量校验、内存页对齐判断)或嵌入式环境。
- GCC/Clang 在
-O2下通常不会把除法循环自动替换成位运算法 - 该位运算法不依赖分支预测,无条件跳转,对流水线更友好
- 对
constexpr场景(编译期计算),位运算法可直接用于模板参数推导,除法法不行
64 位整数和 constexpr 场景下的写法差异
当 n 是 long long 或 uint64_t,n - 1 没问题,但要注意字面量后缀:比如 1LL 避免整型提升错误。更重要的是,若要支持编译期计算(如用在 static_assert 或模板参数中),函数必须声明为 constexpr,且所有操作必须是常量表达式。
以下写法是安全的:
constexpr bool isPowerOfTwo(uint64_t n) {
return n != 0 && (n & (n - 1)) == 0;
}
但若传入变量(非常量表达式),constexpr 函数仍可运行时调用,不影响逻辑。容易踩的坑是:在模板中用它做 SFINAE 判断时,若未加 constexpr 修饰,某些编译器会拒绝实例化。
另外,std::popcount(n) == 1 看似直观,但它依赖 C++20,且底层可能展开为查表或硬件指令(POPCNT),并非所有平台支持,也不如 & 操作普适。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










