C++ 在C/C++; //b:uint32\t大小为n=>32*n位的数组 //位索引i的范围为0.5]|=(1>5]&=(~(1>5]&(1>5;~(b[k])==0;i=(-k

C++ 在C/C++; //b:uint32\t大小为n=>32*n位的数组 //位索引i的范围为0.5]|=(1>5]&=(~(1>5]&(1>5;~(b[k])==0;i=(-k,c++,c,bit-manipulation,C++,C,Bit Manipulation,根据可用存储空间的大小,可以采用查找表方法。例如,如果可以使用256个字节,则以下函数可以为单个uint32\t执行此操作: unsigned idx_of_first_zero_bit_before_or_at (uint32_t *b, unsigned n, unsigned i) { for (unsigned k = i >> 5; ~(b[k]) == 0; i = (--k << 5) + 31); while (get_bit (b, n,

根据可用存储空间的大小,可以采用查找表方法。例如,如果可以使用256个字节,则以下函数可以为单个
uint32\t
执行此操作:

unsigned idx_of_first_zero_bit_before_or_at (uint32_t *b, unsigned n, unsigned i) {
    for (unsigned k = i >> 5; ~(b[k]) == 0; i = (--k << 5) + 31);
    while (get_bit (b, n, i)) 
        i--;
    return i;
}
static const int table[256]={
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0,
};
int func(uint32\u t b,int i)
{
b=(b>24)和0xFF]+24-(31-i)
:表[(b>>16)和0xFF]+16-(31-i);
}
其他的
{
返回((b&0xFF00)!=0xFF00)
?表[(b>>8)和0xFF]+8-(31-i)
:表[(b>>0)和0xFF]+0-(31-i);
}
}
我相信这可以进一步优化。例如,当然有一些方法可以消除昂贵的条件分支;您可以使用布尔条件求值为
1
0
,并将它们用作被乘数

如果您有64kB的可用空间,那么您可以一次对16位数据块执行此操作,以此类推。当然,对大型表执行随机访问可能会产生缓存效果,因此您需要进行实验和分析。

通常我会尝试避免“随机”例如,我们可以采用Oli Charlesworth提出的解决方案,去掉
if
s

它使用a解决了大部分计算,但最后一部分仍然需要分支。引入一个额外的LUT来处理它:

static const int table[256] = { 
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0,
};


int func(uint32_t b, int i)
{
    b = (b << (31-i));

    if ((b & 0xFFFF0000) != 0xFFFF0000)
    {
        return ((b & 0xFF000000) != 0xFF000000)
             ? table[(b >> 24) & 0xFF] + 24 - (31-i)
             : table[(b >> 16) & 0xFF] + 16 - (31-i);
    }
    else
    {
        return ((b & 0xFF00) != 0xFF00)
             ? table[(b >> 8) & 0xFF] + 8 - (31-i)
             : table[(b >> 0) & 0xFF] + 0 - (31-i);
    }
}

此外,通过首先使用16位LUT,我们将得到两个16位查找和一个8位查找。

您可以使用二进制搜索在一个uint32中查找零位。您还可以使用查找表替换最后几个步骤,以平衡LUT的内存占用与指令。首先,一个具有控制流的解决方案:

return table2[index2]; // char[4096] array with precomputed values.
第一个零位(uint32)的无符号idx{ int-idx=0; if(n==0xFFFFFF)返回32;//未找到;可能是常见情况 //二进制搜索 if(n&0xffff==0xffff){ n>>=16; idx+=16; } if(n&0xff==0xff){ n>>=8; idx+=8; } if(n&0xf==0xf){ n>>=4; idx+=4; } if(n&0x3==0x3){ n>>=2; idx+=2; } if(n&0x1==0x1){ n>>=1; idx+=1; } 返回idx; } 为了避免分支预测失误,可以使用逐位操作进行条件更新

unsigned idx_of_first_zero_bit(uint32_t n) { int idx = 0; if (n == 0xffffffff) return 32; // Not found; presumably the common case // Binary search if (n & 0xffff == 0xffff) { n >>= 16; idx += 16; } if (n & 0xff == 0xff) { n >>= 8; idx += 8; } if (n & 0xf == 0xf) { n >>= 4; idx += 4; } if (n & 0x3 == 0x3) { n >>= 2; idx += 2; } if (n & 0x1 == 0x1) { n >>= 1; idx += 1; } return idx; } int移位; //第一步 移位=((n&0xffff==0xffff)>=shift; idx+=移位; //下一步 移位=((n&0xff==0xff)>=shift; idx+=移位;
您未经测试的
get_bit
似乎会检查所有内容(在相关的32位值中),但有问题的位除外。只需忽略反转即可。:-)对于优化,请考虑跳过全部为1的32位值,通过反转和检查0可以轻松检查。谢谢,@Alf:谢谢,尝试添加您的解决方案-可能不尽可能好…GCC有一些扩展,例如内置clz,因此您可以在只需要使用GCC的情况下使用它们。@mu:我已经看过了,但我可以我想不出一个合理的方法来使用它们来实现这个算法(不过,这可能是可能的)。好主意!我将针对我的平台对其进行优化并进行比较。@Thomas:现在您使用的是“跳过所有
0xffffff
s方法”,我怀疑对于足够长的数组,您的运行时将由跳过循环控制。因此,可能不值得对上述例程进行优化…这应该会产生很好的改进。不幸的是,我的平台只有256kB的内存-4096+256字节对于此算法来说已经太多了。
unsigned index2 = table[ b        & 0xFF]        |  // Values 0..7, so we use 3 bits
                 (table[(b >>  8) & 0xFF] << 3 ) |  // Next 3 bits..
                 (table[(b >> 16) & 0xFF] << 6 ) |
                 (table[(b >> 24) & 0xFF] << 9 );
return table2[index2]; // char[4096] array with precomputed values.
unsigned idx_of_first_zero_bit(uint32_t n) { int idx = 0; if (n == 0xffffffff) return 32; // Not found; presumably the common case // Binary search if (n & 0xffff == 0xffff) { n >>= 16; idx += 16; } if (n & 0xff == 0xff) { n >>= 8; idx += 8; } if (n & 0xf == 0xf) { n >>= 4; idx += 4; } if (n & 0x3 == 0x3) { n >>= 2; idx += 2; } if (n & 0x1 == 0x1) { n >>= 1; idx += 1; } return idx; } int shift; // First step shift = ((n & 0xffff == 0xffff) << 4); // shift = (n & 0xffff == 0xffff) ? 16 : 0 n >>= shift; idx += shift; // Next step shift = ((n & 0xff == 0xff) << 3); // shift = (n & 0xff == 0xff) ? 8 : 0 n >>= shift; idx += shift;