在程式設計中,判斷一個正整數 x 是否為 2 的冪次方(即 2n)是一個經典問題。最優雅且高效的解法莫過於位運算表達式:x & (x - 1) == 0。若結果為真,則 x 是 2 的冪次方;否則不是。這個技巧廣泛應用於演算法優化、記憶體對齊檢查等場景。
一個正整數是 2 的冪次方,當且僅當其二進制表示中有且僅有一個 1,其餘皆為 0。例如:
1101001000反之,若非 2 的冪次方,其二進制中至少包含兩個 1。
x & (x - 1) 能判斷?x - 1 運算會將 x 二進制中最右邊的 1 變為 0,並將該 1 右側的所有 0 變為 1。例如:
x = 8 (1000),x - 1 = 7 (0111)x = 12 (1100),x - 1 = 11 (1011)若 x 僅有一個 1(即 2 的冪次方),則 x & (x - 1) 的所有位都為 0,結果為 0。若 x 有多個 1,則最高位的 1 仍保留在結果中,結果非 0。
許多教程只證明「2 的冪次方滿足條件」,卻忽略了逆命題。以下補充完整證明:
X 的二進制為 x₁x₂...xₙ(x₁=1,n>0)。X 是 2 的冪次方 ⇔ 二進制中有且僅有一個 1(即 x₁=1,x₂=...=xₙ=0)。X 不是 2 的冪次方 ⇔ 存在 j (1 使 xⱼ=1。 X = 1 時:1 & 0 = 0,成立。X > 1 時:X = 100...0(n-1 個 0),X-1 = 11...1(n-1 個 1)。按位與運算結果全為 0。分兩種情況討論:
X-1 將最低位變 0,高位不變。按位與運算保留高位的 1,結果非 0。j 位。X-1 將該 1 變 0,右側 0 變 1。按位與運算中,第 j 位變 0,但更高位的 1 保留,結果非 0。bool isPowerOfTwo(int x) {
return x > 0 && (x & (x - 1)) == 0;
}
注意:必須檢查 x > 0,因為 0 和負數不符合定義,且 0 & -1 = 0 會誤判。
& (size-1) 替代取模運算,前提是 size 為 2 的冪次方。這個技巧展示了位運算在演算法設計中的威力:以 O(1) 時間、無分支指令完成判斷,是系統級程式設計的必備技能。