函數 check32(int32_t val):正數返回 1,負數返回 -1,零返回 0。**禁用任何條件分支指令** (if, ?:, switch, 循環 等),純位運算實現。同理實現無符號版本:零返回 0,非零返回 1。
val >> 31 (算術右移,符號位擴展)。負數得 0xFFFFFFFF (-1),非負得 0x00000000 (0)。// 將任意 1 位傳播到最低位
b = (val & 0x0000FFFF) | ((val >> 16) & 0x0000FFFF); // 16 位合併
b = (b & 0x000000FF) | ((b >> 8) & 0x000000FF); // 8 位
b = (b & 0x0000000F) | ((b >> 4) & 0x0000000F); // 4 位
b = (b & 0x00000003) | ((b >> 2) & 0x00000003); // 2 位
b = (b & 0x00000001) | ((b >> 1) & 0x00000001); // 1 位 (LSB)
// b = 0 當且僅當 val == 0;否則 b = 1
return a | b;
a=0, b=1 → 1a=-1, b=1 → -1 (全 1 即 -1)a=0, b=0 → 0
#include
// 有符號 32 位:返回 -1, 0, 1
int32_t check32(int32_t val) {
int32_t a = val >> 31; // 符號掩碼: 0 或 -1
int32_t b = (val & 0x0000FFFF) | ((val >> 16) & 0x0000FFFF);
b = (b & 0x000000FF) | ((b >> 8) & 0x000000FF);
b = (b & 0x0000000F) | ((b >> 4) & 0x0000000F);
b = (b & 0x00000003) | ((b >> 2) & 0x00000003);
b = (b & 0x00000001) | ((b >> 1) & 0x00000001); // 非零檢測: 0 或 1
return a | b; // 合成: 正→1, 負→-1, 零→0
}
// 無符號 32 位:返回 0 或 1
uint32_t check32(uint32_t val) {
uint32_t a = (val & 0x0000FFFF) | ((val >> 16) & 0x0000FFFF);
a = (a & 0x000000FF) | ((a >> 8) & 0x000000FF);
a = (a & 0x0000000F) | ((a >> 4) & 0x0000000F);
a = (a & 0x00000003) | ((a >> 2) & 0x00000003);
a = (a & 0x00000001) | ((a >> 1) & 0x00000001);
return a; // 零→0, 非零→1
}
| 方法 | 代碼 | 優勢 |
|---|---|---|
| GCC/Clang Builtin | return (val > 0) - (val < 0); (無分支優化) | 可讀性強,現代編譯器 (-O2) 自動生成無分支 CMOV/SETcc 指令 |
| x86 BMI2 | _tzcnt_u32 / _lzcnt_u32 | 硬件指令統計前導/尾隨零,間接判斷非零 |
| C++20 | std::signum(val) (C++26 提案) | 標準庫支持 |
(val & 0x80000000) ? -1 : 0 (有分支) 或聯合體/轉無符號邏輯右移後修正。int32_t 恰 32 位。若 int 為 64 位,掩碼需調整。使用 <cstdint> 固定寬度類型。if-else 往往更快。僅在**極端熱點路徑、GPU/SIMD、恒定時間要求 (密碼學)** 場景手寫無分支版本。