最可靠判断2的幂的方法是n > 0 && (n & (n - 1)) == 0,因n ≤ 0时位运算会误判,且log2或循环除2存在精度、性能或代码冗余问题。

用 (n & (n - 1)) == 0 判断是否为 2 的幂最可靠
前提是 n > 0。因为 2 的幂在二进制中只有一位是 1(如 1、10、100),而 n - 1 会把该位变成 0,并把右边所有位变成 1。两者按位与结果必为 0。比如 n = 8(1000),n - 1 = 7(0111),1000 & 0111 == 0000。
常见错误是忽略 n 的情况:<code>0 和负数都会让 n & (n - 1) 返回 0,但它们不是 2 的幂。所以必须显式检查 n > 0。
-
n == 0→ 不是 2 的幂,但(0 & -1) == 0(取决于补码行为,实际中常为 true,造成误判) n → 无意义(2 的幂恒为正整数),但位运算仍会算出结果,必须拦截- 推荐写法:
n > 0 && (n & (n - 1)) == 0
为什么不用 log2(n) 或循环除 2?
浮点函数不精确,尤其对大整数:log2(2^30) 理论上是 30,但因精度丢失可能算成 29.999999,floor 后变 29,再 pow(2, 29) 就错。循环除 2 虽安全,但时间复杂度 O(log n),而位运算是 O(1)。
-
std::log2(n)对int64_t类型在边界值(如1LL )易失准 - 循环写法需处理
n % 2 != 0和n == 1两个退出条件,代码更冗长 - 位运算无需分支预测、无循环开销,CPU 指令级支持,编译器也容易优化
注意无符号数和溢出场景
如果 n 是 unsigned int,n - 1 在 n == 0 时会回绕成全 1(如 0U - 1U == UINT_MAX),此时 n & (n - 1) 变成 0 & UINT_MAX == 0,仍会误判。所以类型不影响逻辑,n > 0 这一判断不可省。
立即学习“C++免费学习笔记(深入)”;
- 对
unsigned类型,n == 0仍需单独排除 - 若
n是int且值为INT_MIN(如-2147483648),n - 1会溢出(未定义行为),所以务必确保输入范围合法或先转为无符号处理 - 安全做法:统一用
unsigned接收,再判断n != 0 && (n & (n - 1)) == 0
扩展:如何获取小于等于 n 的最大 2 的幂?
这是常见配套需求,比如分配内存块或构造线段树。可用位运算清零最低位的 1,直到只剩最高位:
unsigned int floor_pow2(unsigned int n) {
if (n == 0) return 0;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return (n + 1) >> 1;
}原理是把最高位以下全置为 1,再加 1 就进位到下一个 2 的幂,右移一位即得当前最大 2 的幂。比 while 循环快,且无分支。
真正难的不是写出 n & (n - 1),而是记住它只对正整数有效,以及在模板泛型或跨平台代码里,int 和 unsigned 的溢出行为差异会让这个“一行判断”悄悄失效。










