n是2的幂当且仅当n≠0且n&(n−1)=0,因该运算清零最低位1,结果为0说明原数仅含一个1;需排除0,负数由n>0拦截,C++20可用std::has_single_bit。

用 n & (n - 1) 判断是否为2的幂最常用
正整数 n 是2的幂,当且仅当它的二进制表示中只有一个 1(比如 1、10、100 对应 1、2、4)。而 n & (n - 1) 这个位运算会把 n 最低位的 1 清零。所以如果结果为 0,说明原来就只有一个 1。
但必须先排除 n 的情况,因为负数和零不满足“2的正整数次幂”的语义:
-
n == 0→ 不是2的幂,且0 & (0 - 1)是0,会误判 n → 有符号整数下,n - 1可能溢出或产生意外的高位1,结果不可靠
正确写法:
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
为什么不用 log2(n) 或循环除2
std::log2 是浮点运算,存在精度问题:比如 n = 1 (8388608),某些平台下 std::log2(n) 可能返回 23.000000000000004 或 22.999999999999996,std::floor 或取整后容易错判。
循环除2虽然直观,但效率低,尤其对大数;还得多写几行处理边界(如 n == 1、n % 2 != 0 等)。
- 位运算是常数时间、无分支、CPU 友好
- 编译器通常能将
n & (n - 1)优化成单条指令(如 x86 的and) - 对
unsigned int同样适用,且无需担心负数问题
注意 int 和 unsigned 的行为差异
当 n 是有符号 int 时,n == INT_MIN(即 -2147483648)会导致 n - 1 溢出,触发未定义行为。所以务必先做 n > 0 判断,它会在溢出前拦住所有非正数。
若输入类型是 unsigned int,则 n - 1 是模运算,不会溢出,但仍要排除 n == 0:
bool isPowerOfTwo(unsigned int n) {
return n != 0 && (n & (n - 1)) == 0;
}
另外,C++20 起可直接用 std::has_single_bit(n)(需 #include ),它内部就是基于 n & (n - 1) 实现的,但要注意它对 0 返回 false,符合预期。
实际调试时最容易漏掉的检查点
写完函数别急着提交,快速过一遍这几个值:
-
isPowerOfTwo(0)→ 必须为false -
isPowerOfTwo(1)→ 必须为true(2^0) -
isPowerOfTwo(-1)→ 必须为false(有符号时,n > 0直接拦截) -
isPowerOfTwo(INT_MIN)→ 不应进入位运算分支,否则 UB
如果用在模板函数里泛化到 long long,记得把字面量 0 写成 0LL 或用 decltype(n)(0) 避免隐式转换警告;不过更稳妥的是统一用 n != 0 配合类型推导。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











