int countOnes(int x) {
int cnt = 0;
while (x) {
++cnt;
x &= (x - 1); // 清除最低位的 1
}
return cnt;
}
// 示例:x = 9999 (二進制 10011100001111) → 8 個 1
原理:x-1 將最低位 1 變為 0,該位右側所有 0 變為 1。x & (x-1) 保留高位不變,最低位 1 清零,右側全 0。每次循環消除一個 1,循環次數即為 1 的個數 (Hamming Weight)。
應用:判斷 2 的冪次 (x & (x-1) == 0)、子集枚舉、位圖操作。
unsigned char avg(unsigned char x, unsigned char y) {
return (x & y) + ((x ^ y) >> 1);
}
// 測試
avg(2, 8) // 5
avg(5, 5) // 5
avg(5, 6) // 5
avg(255, 255) // 255 (不溢出!)
推導:逐位分解平均值 (x+y)/2:
1+1=2,平均 1 → x & y 保留這些位。1+0=1,平均 0.5 → 向下取整 0,但進位影響鄰位。(x ^ y) >> 1 將異或結果右移,正好是這些位貢獻的進位部分。優勢:無中間和溢出風險,適用於定寬整數類型 (如 uint8_t、uint16_t) 的匯編/嵌入式場景。
float a = 1.0f;
std::cout << (int)a; // 1 (值轉換:浮點數 1.0 → 整數 1)
std::cout << (int&a); // 1065353216 (位模式重解釋:IEEE 754 0x3F800000 → 整數)
float b = 0.0f;
std::cout << (int)b; // 0
std::cout << (int&b); // 0 (0.0f 位模式全 0)
本質區別:
(int)a:值轉換,按語義將浮點數值轉為整數值,生成新對象。(int&a):類型重解釋 (Reinterpret Cast),告訴編譯器「將這塊內存當作 int 看待」,不改變比特位,屬於 reinterpret_cast<int&>(a)。嚴重警告:
std::memcpy、std::bit_cast (C++20)、union (C++ 標準允許聯合體類型雙向轉換)。
// 安全做法 C++20
#include <bit>
int bits = std::bit_cast<int>(1.0f); // 1065353216
// C++17 兼容
int bits;
static_assert(sizeof(float) == sizeof(int));
std::memcpy(&bits, &a, sizeof(a));
| 表達式 | 功能 | 核心原理 | 現代 C++ 替代 |
|---|---|---|---|
x & (x-1) | 清除最低位 1 / 計數 1 的個數 | 二進制減法借位特性 | std::popcount (C++20) |
(x&y)+((x^y)>>1) | 無溢出平均值 | 逐位分解加法進位 | (x+y)>>1 (無符號安全) / std::midpoint (C++20) |
(int&a) | 位模式重解釋 | 違反嚴格別名規則 (UB) | std::bit_cast / memcpy |
popcount, midpoint, bit_cast),可讀、安全、編譯器優化最好。(Type&) 進行類型重解釋,改用 reinterpret_cast 明確意圖 (仍需承擔 UB 風險)。1.0f = 0x3F800000。