C 寻找第一个可用位的最佳方法
给定一个非单整数数组(每个有4个八位组),找到第一个至少有一个“0”位的元素及其LSB索引的最佳方法是什么 e、 g:式中n=9C 寻找第一个可用位的最佳方法,c,C,给定一个非单整数数组(每个有4个八位组),找到第一个至少有一个“0”位的元素及其LSB索引的最佳方法是什么 e、 g:式中n=9 unsinged int uIntArray[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff9f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; 答复: 我只能想
unsinged int uIntArray[] = {
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
0xffffff9f,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
答复:
我只能想到:
int main (void)
{
bool found_f = false;
int n = 9; //our test case value
unsigned int uIntArray[] = {
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
0xffffff8f,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
unsigned int uIntBits [32] = {
1, 2, 4, 8, 16, 32, 64, 128,
256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648
};
unsigned int idx, jdx;
int ele_idx = -1;
int bit_idx = -1;
for (idx =0; idx < n; idx ++) {
if (uIntArray[idx] < UINT_MAX) { /* our candidate */
for (jdx =0; jdx < 32; jdx ++) {
if ((uIntBits[jdx] & uIntArray[idx])) {
ele_idx = idx;
bit_idx = jdx;
found_f = true;
break;
}
}
}
if(found_f) {
break;
}
}
fprintf (stderr, "\nEleIdx[%d] BitIdx[%d]\n", ele_idx, bit_idx);
return 0;
}
int main(无效)
{
bool found_f=false;
int n=9;//我们的测试用例值
无符号整数uIntArray[]={
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
0xFFFF8F,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
无符号整数uIntBits[32]={
1, 2, 4, 8, 16, 32, 64, 128,
256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648
};
无符号整数idx,jdx;
int ele_idx=-1;
int位_idx=-1;
对于(idx=0;idx
有更好的方法吗?您可以通过使用更大的数据类型来加快速度。因此,不必测试每个
int
是否为0xffffffff
,您可以使用64位整数并根据0xffffffffffff
进行测试
如果您愿意矢量化,您可以一次执行128位(SSE)或256位(AVX)
在所有情况下,注意数据对齐。如果不对齐,它要么无法工作,要么会使速度变慢
最后一步,您可以实际展开循环并一次测试多个单词/向量。这会给你更好的IPC。只有当你找到零时,你才会经历一个混乱的过程,缩小它是哪一位
编辑:
为了说明最后一点,您可以这样做:(我省略了案例idx%4!=0时的清理代码)
for(idx=0;idx
但您可以在更大的数据类型上执行此操作。(如SSE/AVX向量)
这将使查找前0的区域更快,但缩小精确位的范围将更昂贵。因此,如果您的数据量较大,这种方法会更好。您可以通过使用较大的数据类型来加快速度。因此,不必测试每个int
是否为0xffffffff
,您可以使用64位整数并根据0xffffffffffff
进行测试
如果您愿意矢量化,您可以一次执行128位(SSE)或256位(AVX)
在所有情况下,注意数据对齐。如果不对齐,它要么无法工作,要么会使速度变慢
最后一步,您可以实际展开循环并一次测试多个单词/向量。这会给你更好的IPC。只有当你找到零时,你才会经历一个混乱的过程,缩小它是哪一位
编辑:
为了说明最后一点,您可以这样做:(我省略了案例idx%4!=0时的清理代码)
for(idx=0;idx
但您可以在更大的数据类型上执行此操作。(如SSE/AVX向量)
这将使查找前0的区域更快,但缩小精确位的范围将更昂贵。因此,如果您的数据量很大,这种方法会更好。要找到第一个元素,您可以观察到,如果数字没有0
位,那么它必须是0xff..ff
,因此不必显式检查每个位,只需将其与0xff..ff
进行比较即可
要找到该数字的最低有效位,我相信您仍然需要检查每个位。要找到第一个元素,您可以观察到,如果该数字没有0
位,那么它必须是0xff..ff
,因此不必显式检查每个位,您只需将其与0xff..ff
进行比较即可
要找到该数字的最低有效位,我相信您仍然需要检查每个位。在x
中最低有效0
的索引是~x
中最低有效1
的索引。为了找到后者,只需计算~x
中的尾随零。有很多方法可以做到这一点,请看这里
使用最后一种方法(基于Debrijn序列),搜索将如下所示
static const unsigned MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
for (idx = 0; idx < n; idx ++)
if (uIntArray[idx] < UINT_MAX)
break;
if (idx < n) {
unsigned v = ~uIntArray[idx];
int bit_idx = MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531u) >> 27];
fprintf(stderr, "\nEleIdx[%d] BitIdx[%d]\n", idx, bit_idx);
}
static const unsigned multipledbruijnbitposition[32]=
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
对于(idx=0;idx>27];
fprintf(stderr,“\nEleIdx[%d]BitIdx[%d]\n”,idx,bit_idx);
}
在x
中最低有效0
的索引是~x
中最低有效1
的索引。为了找到后者,只需计算~x
中的尾随零。有很多方法可以做到这一点,请看这里
使用最后一种方法(基于Debrijn序列),搜索
for (idx =0; idx < n; idx += 4) {
unsigned int test = uIntArray[idx];
test &= uIntArray[idx + 1];
test &= uIntArray[idx + 2];
test &= uIntArray[idx + 3];
if (test < UINT_MAX){
// Find which bit it is.
}
}
static const unsigned MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
for (idx = 0; idx < n; idx ++)
if (uIntArray[idx] < UINT_MAX)
break;
if (idx < n) {
unsigned v = ~uIntArray[idx];
int bit_idx = MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531u) >> 27];
fprintf(stderr, "\nEleIdx[%d] BitIdx[%d]\n", idx, bit_idx);
}
/* Return the position of the first clear bit in the array,
* or -1 if none found.
* arr: array of uint32_t to search
* sz: number of elements in arr
*/
int findClearBit(uint32_t *arr, int sz)
{
int i;
for (i = 0; i < sz; i++) {
if (~arr[i]) {
switch (~arr[i] & (arr[i] + 1)) {
case 1 << 31: return (i * 32) + 31;
case 1 << 30: return (i * 32) + 30;
case 1 << 29: return (i * 32) + 29;
case 1 << 28: return (i * 32) + 28;
case 1 << 27: return (i * 32) + 27;
case 1 << 26: return (i * 32) + 26;
case 1 << 25: return (i * 32) + 25;
case 1 << 24: return (i * 32) + 24;
case 1 << 23: return (i * 32) + 23;
case 1 << 22: return (i * 32) + 22;
case 1 << 21: return (i * 32) + 21;
case 1 << 20: return (i * 32) + 20;
case 1 << 19: return (i * 32) + 19;
case 1 << 18: return (i * 32) + 18;
case 1 << 17: return (i * 32) + 17;
case 1 << 16: return (i * 32) + 16;
case 1 << 15: return (i * 32) + 15;
case 1 << 14: return (i * 32) + 14;
case 1 << 13: return (i * 32) + 13;
case 1 << 12: return (i * 32) + 12;
case 1 << 11: return (i * 32) + 11;
case 1 << 10: return (i * 32) + 10;
case 1 << 9: return (i * 32) + 9;
case 1 << 8: return (i * 32) + 8;
case 1 << 7: return (i * 32) + 7;
case 1 << 6: return (i * 32) + 6;
case 1 << 5: return (i * 32) + 5;
case 1 << 4: return (i * 32) + 4;
case 1 << 3: return (i * 32) + 3;
case 1 << 2: return (i * 32) + 2;
case 1 << 1: return (i * 32) + 1;
case 1: return (i * 32);
default: return -1;
}
}
}
return -1;
}