n > 0 && (n & (n - 1)) == 0 可判断2的幂,因2的幂二进制仅一个1,n-1使该1变0且右端全为1,按位与必为0;需排除n≤0情况,避免补码干扰或未定义行为。

为什么 n & (n - 1) == 0 能判断 2 的幂
核心就一条:2 的正整数次幂,二进制里**只有一个 1**,比如 4 是 100,8 是 1000。而 n - 1 会把那个唯一的 1 变成 0,并把右边所有位变成 1 —— 这个结构天然和原数“错开”。& 运算要求两位都为 1 才得 1,所以结果必为 0。
举个例子:8 & 7 → 1000 & 0111 == 0000;但 6 & 5 → 0110 & 0101 == 0100 != 0,因为 6 有两个 1,减 1 后没法清空全部。
n > 0 这个条件不能省
漏掉这个判断会出严重问题:
-
0 & (0 - 1)在有符号整数下是0 & (-1),而-1补码全为 1,结果不为 0,但 0 显然不是 2 的幂 - 负数如
-4,-4 & -5可能碰巧为 0(取决于补码表示),但负数根本不在定义域内 - 所以必须前置检查:
n > 0,否则整个逻辑失效
C/C++ 里 n & -n == n 也能用,但要注意类型
这个技巧依赖补码特性:-n 等价于 ~n + 1,当 n 只有一个 1 时,n & -n 恰好等于 n。但它对无符号数更安全:
- 用
unsigned int时,-n是模运算,行为确定 - 用
int时,-n对INT_MIN会溢出(未定义行为) - 所以更推荐第一种写法:
n > 0 && (n & (n - 1)) == 0,兼容性好、意图清晰、无溢出风险
别拿浮点函数 log2 来凑数
有人想用 log2(n) 看是否为整数,这在工程中基本不可靠:
-
log2(2^24)在 float 下可能精度丢失,floor判断失败 - 需要包含
,链接 math 库,增加依赖 - 浮点运算比位运算是数量级慢,且无法做编译期常量判断(比如
static_assert) - 整数位运算零开销,一个指令就能搞定,没必要绕路
真正容易被忽略的是边界组合:比如 n = 1(即 2^0)必须被接受,而 1 & 0 == 0 成立,所以该公式天然支持;但若手写循环除 2,常有人忘了处理 n == 1 直接返回 true 的情况。










