首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

無分支判斷整數符號:位運算實現有符號/無符號 32 位整數正負零檢測

     編輯:關於C語言

題目要求

函數 check32(int32_t val):正數返回 1,負數返回 -1,零返回 0。**禁用任何條件分支指令** (if, ?:, switch, 循環 等),純位運算實現。同理實現無符號版本:零返回 0,非零返回 1。

核心思路:符號位與「任意位為 1」檢測分離

  1. 符號位提取:val >> 31 (算術右移,符號位擴展)。負數得 0xFFFFFFFF (-1),非負得 0x00000000 (0)。
  2. 非零檢測 (值部分):將 32 位壓縮為 1 位 — 並行前綴 OR (Parallel Prefix OR) / SWAR (SIMD Within A Register) 技術:
// 將任意 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
  1. 合成結果:return a | b;
    • val > 0: a=0, b=1 → 1
    • val < 0: a=-1, b=1 → -1 (全 1 即 -1)
    • val = 0: a=0, b=0 → 0

完整實現 (C/C++ 標準整數類型)


#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 Builtinreturn (val > 0) - (val < 0); (無分支優化)可讀性強,現代編譯器 (-O2) 自動生成無分支 CMOV/SETcc 指令
x86 BMI2_tzcnt_u32 / _lzcnt_u32硬件指令統計前導/尾隨零,間接判斷非零
C++20std::signum(val) (C++26 提案)標準庫支持

避坑指南

  • 算術右移保證:C 標準未強制有符號右移為算術移位,但主流編譯器 (GCC, MSVC, Clang) 均實現為算術移位。嚴格移植需用 (val & 0x80000000) ? -1 : 0 (有分支) 或聯合體/轉無符號邏輯右移後修正。
  • 類型寬度:代碼假設 int32_t 恰 32 位。若 int 為 64 位,掩碼需調整。使用 <cstdint> 固定寬度類型。
  • 性能權衡:手寫 SWAR 共 10 條指令 (AND, OR, SHR);現代 CPU 分支預測極強,簡單 if-else 往往更快。僅在**極端熱點路徑、GPU/SIMD、恒定時間要求 (密碼學)** 場景手寫無分支版本。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved