获得第k个位置位置的最快方法

时间:2016-07-30 04:50:00

标签: c assembly optimization x86 bit-manipulation

想象一下,我们给出了一个整数排序序列,它作为一个位集存储在一个32位或64位整数中。例如:

  sequence = 0, 2, 3, 5, 6, 8, 11, 14;
  mask = 1011011010010010;
  16-bit bitset = 0100100101101101b = 0x496D;

序列中的每个整数都有 index ,它等于它之前的整数,以及 position ,它只是整数的值。相同的术语可以应用于相应位集中的任何设置位。例如,在上面的示例中,设置位为 position = 2 index = 1 ,并且 position = 8 指数= 5

使用popcnt指令,我们可以在现代x86架构中轻松找到 position 中的设置位的 index ,如下所示:

uint32_t position_to_index(uint32_t bset, uint32_t pos) {
    (a) return _mm_popcnt_u32(_bzhi_u32(bset, pos));      //BMI2 & POPCNT
    (b) return _mm_popcnt_u32(bset & ((1 << pos) - 1)));  //POPCNT only
}

显然,它也适用于任何其他支持硬件popcount的架构。

问题是:如何有效地计算反函数,它通过给定的索引k返回给定整数中第k个设置位的位置?

为简单起见,可以假设在给定的位集中确实存在具有指定索引的设置位,即不需要进行错误检查。期望随机输入比特集的快速性能,因此所谓的无分支解决方案将是好的。欢迎使用特定于硬件的指令。小型(但随机分布)指数的快速解决方案也很有意思。

这是一个简单的基本解决方案,适用于小型索引:

uint32_t index_to_position(uint32_t bset, uint32_t idx) {
    for (uint32_t i = 0; i < idx; i++)
        (a) bset = _blsr_u32(bset);    //BMI1
        (b) bset = bset & (bset - 1);  //pure C
    return _bit_scan_forward(bset);    //bsf (>=386)
}

0 个答案:

没有答案