You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

快速__m256i位运算:查找或清除最高/最低置位

针对__m256i的快速位运算实现方案

以下是基于AVX/AVX2指令集,针对256位向量__m256i的5种位运算高效实现:


1. 清除最低置位(整个256位向量)

基于x & (x - 1)的核心逻辑,处理跨64位元素的借位情况:

__m256i clear_global_lowest_set_bit(__m256i x) {
    __m256i one = _mm256_set1_epi64x(1);
    __m256i x_minus_1 = _mm256_sub_epi64(x, one);
    
    // 检测减1后变为全1的元素(即原元素为0,产生借位)
    __m256i borrow_mask = _mm256_cmpeq_epi64(x_minus_1, _mm256_set1_epi64x(0xFFFFFFFFFFFFFFFF));
    // 将借位掩码左移63位,传递到高位元素的最低位
    borrow_mask = _mm256_slli_epi64(borrow_mask, 63);
    // 生成处理跨元素借位后的掩码
    __m256i mask = _mm256_or_si256(x_minus_1, borrow_mask);
    
    return _mm256_and_si256(x, mask);
}

若需对每个64位元素单独清除最低置位,直接返回_mm256_and_si256(x, x_minus_1)即可。

2. 清除最高置位(整个256位向量)

先定位全局最高置位的位置,再构造掩码清除该位:

__m256i clear_global_highest_set_bit(__m256i x) {
    // 反转64位元素顺序,方便从高到低查找非零元素
    __m256i reversed_x = _mm256_permute4x64_epi64(x, 0x0F);
    // 提取每个元素的最高位作为字节掩码
    __m256i highest_bits = _mm256_srli_epi64(reversed_x, 63);
    int bit_mask = _mm256_movemask_epi8(highest_bits);
    
    // 找到最高置位的字节位置,计算全局位索引
    int byte_pos = 31 - __builtin_clz(bit_mask);
    int global_bit_pos = (3 - byte_pos/8)*64 + 63 - (byte_pos%8)*8;
    
    // 构造对应位为0的掩码
    uint64_t mask_elem = ~(1ULL << (global_bit_pos % 64));
    __m256i mask;
    switch(global_bit_pos / 64) {
        case 0: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, mask_elem); break;
        case 1: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, mask_elem, 0xFFFFFFFFFFFFFFFF); break;
        case 2: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, mask_elem, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); break;
        case 3: mask = _mm256_set_epi64x(mask_elem, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); break;
        default: mask = x;
    }
    
    return _mm256_and_si256(x, mask);
}

若需对每个64位元素单独清除最高置位,可对每个元素执行x ^ (x & (-x))的向量版本。

3. 清除指定位置i(0≤i<256)的位

直接构造目标位为0的掩码,与原向量按位与:

__m256i clear_bit_at_pos(__m256i x, int i) {
    if (i < 0 || i >= 256) return x;
    
    int elem_idx = i / 64;
    int bit_offset = i % 64;
    uint64_t mask_elem = ~(1ULL << bit_offset);
    
    __m256i mask;
    switch(elem_idx) {
        case 0: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, mask_elem); break;
        case 1: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, mask_elem, 0xFFFFFFFFFFFFFFFF); break;
        case 2: mask = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, mask_elem, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); break;
        case 3: mask = _mm256_set_epi64x(mask_elem, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); break;
        default: mask = x;
    }
    
    return _mm256_and_si256(x, mask);
}

4. 查找最低置位的全局位置(输入非零)

先定位第一个非零的64位元素,再在元素内查找最低置位:

int find_global_lowest_set_bit_pos(__m256i x) {
    __m256i zero = _mm256_setzero_si256();
    __m256i cmp = _mm256_cmpeq_epi64(x, zero);
    // 生成非零元素的掩码,从低到高查找第一个非零元素
    int cmp_mask = ~_mm256_movemask_epi8((__m256i)_mm256_castsi256_ps(cmp));
    int first_nonzero_elem = __builtin_ctz(cmp_mask) / 8;
    
    uint64_t elem;
    switch(first_nonzero_elem) {
        case 0: elem = _mm256_extract_epi64(x, 0); break;
        case 1: elem = _mm256_extract_epi64(x, 1); break;
        case 2: elem = _mm256_extract_epi64(x, 2); break;
        case 3: elem = _mm256_extract_epi64(x, 3); break;
        default: elem = 0;
    }
    
    return first_nonzero_elem * 64 + __builtin_ctzll(elem);
}

5. 查找最高置位的全局位置(输入非零)

先定位最后一个非零的64位元素,再在元素内查找最高置位:

int find_global_highest_set_bit_pos(__m256i x) {
    __m256i zero = _mm256_setzero_si256();
    __m256i cmp = _mm256_cmpeq_epi64(x, zero);
    // 生成非零元素的掩码,从高到低查找最后一个非零元素
    int cmp_mask = ~_mm256_movemask_epi8((__m256i)_mm256_castsi256_ps(cmp));
    int last_nonzero_elem = (31 - __builtin_clz(cmp_mask)) / 8;
    
    uint64_t elem;
    switch(last_nonzero_elem) {
        case 0: elem = _mm256_extract_epi64(x, 0); break;
        case 1: elem = _mm256_extract_epi64(x, 1); break;
        case 2: elem = _mm256_extract_epi64(x, 2); break;
        case 3: elem = _mm256_extract_epi64(x, 3); break;
        default: elem = 0;
    }
    
    return last_nonzero_elem * 64 + (63 - __builtin_clzll(elem));
}

内容的提问来源于stack exchange,提问作者user2052436

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:51:02