比较两个整数列表中每个位置的位数

时间:2016-03-17 09:40:57

标签: c bit-manipulation

我遇到了一个问题,我可以通过不同的方式安排我的算法,但这很有趣,也许你们其中一个人有个好主意。

情况如下:我有两个无符号长整数列表,两个列表具有相同的大小,如果这有用,你可以假设这个大小是2的幂。这些列表的大小通常在几百个范围内。现在我想计算一个整数,在每个位置都有一个设置位,其中第一个列表的设置位数多于第二个列表。

速度就是一切。

Simplified example:

list1   list2

1010    0101
1111    0000
1100    0011
1010    0101

result: 1010
because of 4>0, 2<=2, 3>1, 1<=3

编辑:数据的替代排列将导致位向量包含现在几个不同向量中某个位置的位。在那种情况下,我可以使用bit counting algorithm然后进行比较,这相当于两个列表中每64位少于30次操作。基本上我有一个位矩阵,我可以使用位向量作为列或行。

其他结构:John Willemse的评论让我意识到我可以计算出第三个列表,这样这三个列表就可以相互补充。虽然我不知道这会有什么帮助。

2 个答案:

答案 0 :(得分:1)

您可以使用转置计数器 - 而不是为数据的每个位位置设置一个int,而是为计数的每个位位置设置一个uint。希望你不需要太多的东西..

然后,您可以按照它们在bitvectors上定义的方式进行加法/减法,每个&#34; bit&#34;在所有方面都真的是那个位置的一部分。

也许这听起来很模糊,所以让我们直接进入:(未经测试)

// add in item from list2
carry0 = count0 & item2;
count0 ^= item2;
carry1 = count1 & carry0;
count1 ^= carry0;
.. etc for however many bits you need in your counters
// subtract item from list1
borrow0 = ~count0 & item1;
count0 ^= item1;
borrow1 = ~count1 & borrow0;
count1 ^= borrow0;
.. etc

结果是标志,所以你正在使用的最后一个计数器。

或者,完全不同:也许您可以使用int,SWAR样式的子字段。这只适用于字段很小或者您不需要很多字段的情况,因为没有太多空间。使用4位项目并不是那么糟糕,uint32_t提供4个计数器,范围从-128到127,这可能就足够了(最终差异必须在该范围内,中间结果可以安全地包裹)

无论如何它是如何工作的,你用一个查找表或pdep,(未测试)

传播比特
uint32_t spread = _pdep_u32(item, 0x01010101);
// or
uint32_t table[] = {
    0x00000000, 0x00000001, 0x00000100, 0x00000101,
    0x00010000, 0x00010001, 0x00010100, 0x00000101,
    0x01000000, 0x01000001, 0x01000100, 0x00000101,
    0x01010000, 0x01010001, 0x01010100, 0x01010101 };
uint32_t spread = table[item];

然后进行SWAR加法或减法,但它可以稍微优化一下,因为你知道它们会增加或减少或没有变化,(未经测试)

// add in spread item 2
uint32_t H = 0x80808080;
count = ((count &~H) + sp2) ^ (count & H);
// subtract spread item 1
count = ((count | H) - sp1) ^ (~count & H);

结果是每个子字段的符号,这很容易提取但是很难压缩(除非你有pext)。

答案 1 :(得分:0)

它可能不是最有效的,但这是首先想到的解决方案,即O(n)。

int list1[4] = {10, 15, 12, 10};
int list2[4] = {5, 0, 3, 5};

int i, j;
int result = 0;
int num_bits = 4;
int num_elements = 4;

for (i = num_bits - 1; i >= 0; i--)
{
    int bit_pos_ans = 0;
    for (j = 0; j < num_elements; j++)
    {
        /* This works by adding the 1s in list1, and subtracting the 1s in list 2 */
        bit_pos_ans += (((list1[j] >> i) & 0x1) - ((list2[j] >> i) & 0x1));
    }

    /* If there are more 1s in list1 and list2, then this bit position is a 1. */
    if (bit_pos_ans > 0)
    {
        result += 1;
    }

    /* Only shift if this is not calculating bit position 0 */
    if (i > 0)
    {
        result <<= 1;
    }
}

printf("%d", result);
相关问题