C++ 在C/C++; //b:uint32\t大小为n=>32*n位的数组 //位索引i的范围为0.5]|=(1>5]&=(~(1>5]&(1>5;~(b[k])==0;i=(-k
根据可用存储空间的大小,可以采用查找表方法。例如,如果可以使用256个字节,则以下函数可以为单个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,
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;