垂直按位COUNT(相同位置的总和)

时间:2016-03-04 19:12:05

标签: c++ c algorithm bit-manipulation

在许多变量中,是否有任何有效的方法可以在同一位置执行COUNT个? count函数应该用相应位数的1之和填充数组。例如,我们有以下三个变量(我使用8位变量使其变得简单):

uint8_t a = 0xF;  // 0000 1111
uint8_t b = 0x3C; // 0011 1100
uint8_t c = 0xF0; // 1111 0000

int result[8];

// some operations ...

count << result[0] << result[1] << .... // prints 1122 2211

我找到了许多解决方案,用于对整个单变量中的那些进行求和,但不是针对上述问题。

6 个答案:

答案 0 :(得分:2)

这个小代码完全符合您的要求。您可以通过一个小查找数组轻松扩展它以支持N个变量。注意使用double not操作。将输出拖动为0或1。

#include <iostream>

using namespace std;

int main() {
    uint8_t a = 0xF;  // 0000 1111
    uint8_t b = 0x3C; // 0011 1100
    uint8_t c = 0xF0; // 1111 0000

    unsigned result[8];
    for(int i = 0; i < 8; ++i) {
        unsigned mask = 1 << i;
        result[i] = !!(a & mask) + !!(b & mask) + !!(c & mask);
    }

    for(int i = 0; i < 8; ++i)
        cout << result[i];
}

答案 1 :(得分:2)

将每个uint8_t二进制数字扩展为uint32_t十六进制数字,并且#34;将它们加起来&#34;。好,只要每位不超过15个。

#include <stdio.h>
#include <stdint.h>

// See below for tighter code
uint32_t shift_nibble(uint8_t x) {
  uint32_t y = 0;
  uint32_t mask = 1;
  while (x) {
    if (x & 1) {
      y |= mask;
    }
    mask <<= 4;
    x >>= 1;
  }
  return y;
}

void PrintVerticalBitwiseCount(const  uint8_t *x, size_t size) {
  uint32_t y = 0;
  for (size_t i=0; i<size; i++) {
    y += shift_nibble(x[i]);
  }
  printf("%08lX\n", (unsigned long) y);
}

int main(void) {
  const uint8_t a[] = { 0xF, 0x3C,  0xF0 };
  PrintVerticalBitwiseCount(a, sizeof a/sizeof *a);
  return 0;
}

输出

11222211

候选人shift_nibble()更快。戴上你的八角帽

uint32_t shift_nibble(uint8_t x) {
  uint32_t y;
  y  = UINT32_C(0x01010101) & (UINT32_C(0001010101) * (x & 0x55));
  y |= UINT32_C(0x10101010) & (UINT32_C(0010101010) * (x & 0xAA));
  return y;
}

答案 2 :(得分:1)

作为模板,我建议在C ++ 11中使用以下函数。返回的列表在每个位的适当位置具有位计数,也就是说,最低有效位计数在位置0,下一位在位置1处等。 希望这有助于某人。

template<typename T>
std::list<long>
vertical_bit_sum(std::vector<T> items)
{
    size_t bits = sizeof(T) * 8;
    std::list<long> result;
    do
    {
        long count = 0;
        for ( T item : items)
        {
            count += (0x1 & (item >> (bits-1)));
        }

        result.push_front (count);
        --bits;
    }
    while( bits > 0);

    return result;
}

std::list<long> result= vertical_bit_sum<uint8_t>( { 0xF, 0x3C, 0xF0  });

答案 3 :(得分:0)

做这样的事情:

uint64_t accum = 0;
uint64_t table[0x100] = {.. precomputed vals ...};
int count = 0xFF;
while(bytes_available()) {
  if(--count == 0) {
    count = 0xFF;
    for(int i = 0; i < 8; i++)
      result[i] = ((uint8_t*)&accum)[i];
    accum = 0;
  }
  accum += table[(uint8_t)get_next_byte()];
}

答案 4 :(得分:0)

对于绝对速度,您可以通过将8个字节打包在一个64位累加器中来并行处理8个计数。

使用256个64位条目初始化查找表,这些条目是扩展为字节的原始8位。 (例如,条目Lookup[0x17u]映射到0x0000000100010101ul。)

只需使用

执行计数
Acc+= Lookup[Byte];

通过在64位上映射8字节的数组来检索各个计数器。

在溢出发生之前,您可以执行256次累积;如果需要更多,则以256个块累加,并在处理一个块后,将计数传输到更大的累加器。

如果你需要积累不超过16次,32位累加器就足够了。

答案 5 :(得分:-1)

确定变量中某个特定位置的1是否比正常人口计数简单得多。

bool hasOneAtPosition(int position, int target) {
    int mask = 1 << position;
    return (target & mask) != 0;
}

...只需在所有输入上调用它,并在每次返回true时递增计数器。 Simplez。