如何仅使用按位运算符实现 Bitcount?

发布于 2024-09-25 17:41:37 字数 292 浏览 1 评论 0原文

任务是仅使用按位运算符实现位计数逻辑。我让它工作得很好,但我想知道是否有人可以建议一种更优雅的方法。

只允许按位运算。没有“如果”、“因为”等,

int x = 4;

printf("%d\n", x & 0x1);
printf("%d\n", (x >> 1) & 0x1);
printf("%d\n", (x >> 2) & 0x1);
printf("%d\n", (x >> 3) & 0x1);

谢谢。

The task is to implement a bit count logic using only bitwise operators. I got it working fine, but am wondering if someone can suggest a more elegant approach.

Only Bitwise ops are allowed. No "if", "for" etc

int x = 4;

printf("%d\n", x & 0x1);
printf("%d\n", (x >> 1) & 0x1);
printf("%d\n", (x >> 2) & 0x1);
printf("%d\n", (x >> 3) & 0x1);

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云归处 2024-10-02 17:41:37

来自 http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel< /a>

unsigned int v; // count bits set in this (32-bit value)
unsigned int c; // store the total here

c = v - ((v >> 1) & 0x55555555);
c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
c = ((c >> 4) + c) & 0x0F0F0F0F;
c = ((c >> 8) + c) & 0x00FF00FF;
c = ((c >> 16) + c) & 0x0000FFFF;

编辑:不可否认,它进行了一些优化,这使得它更难以阅读。更容易理解为:

c = (v & 0x55555555) + ((v >> 1) & 0x55555555);
c = (c & 0x33333333) + ((c >> 2) & 0x33333333);
c = (c & 0x0F0F0F0F) + ((c >> 4) & 0x0F0F0F0F);
c = (c & 0x00FF00FF) + ((c >> 8) & 0x00FF00FF);
c = (c & 0x0000FFFF) + ((c >> 16)& 0x0000FFFF);

这五个步骤中的每一步,将相邻位以 1、然后 2、然后 4 等为一组添加在一起。
该方法基于分而治之。

在第一步中,我们将位 0 ​​和 1 加在一起,并将结果放入两位位段 0-1 中,将位 2 和 3 添加并将结果放入两位位段 2-3 中,依此类推...

在第二步中我们将两位 0-1 和 2-3 加在一起,并将结果放入四位 0-3,将两位 4-5 和 6-7 加在一起,并将结果放入四位 4-7 等等...

示例:

So if I have number 395 in binary 0000000110001011 (0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1)
After the first step I have:      0000000101000110 (0+0 0+0 0+0 0+1 1+0 0+0 1+0 1+1) = 00 00 00 01 01 00 01 10
In the second step I have:        0000000100010011 ( 00+00   00+01   01+00   01+10 ) = 0000 0001 0001 0011
In the fourth step I have:        0000000100000100 (   0000+0001       0001+0011   ) = 00000001 00000100
In the last step I have:          0000000000000101 (       00000001+00000100       )

等于 5,这是正确的结果

From http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel

unsigned int v; // count bits set in this (32-bit value)
unsigned int c; // store the total here

c = v - ((v >> 1) & 0x55555555);
c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
c = ((c >> 4) + c) & 0x0F0F0F0F;
c = ((c >> 8) + c) & 0x00FF00FF;
c = ((c >> 16) + c) & 0x0000FFFF;

Edit: Admittedly it's a bit optimized which makes it harder to read. It's easier to read as:

c = (v & 0x55555555) + ((v >> 1) & 0x55555555);
c = (c & 0x33333333) + ((c >> 2) & 0x33333333);
c = (c & 0x0F0F0F0F) + ((c >> 4) & 0x0F0F0F0F);
c = (c & 0x00FF00FF) + ((c >> 8) & 0x00FF00FF);
c = (c & 0x0000FFFF) + ((c >> 16)& 0x0000FFFF);

Each step of those five, adds neighbouring bits together in groups of 1, then 2, then 4 etc.
The method is based in divide and conquer.

In the first step we add together bits 0 and 1 and put the result in the two bit segment 0-1, add bits 2 and 3 and put the result in the two-bit segment 2-3 etc...

In the second step we add the two-bits 0-1 and 2-3 together and put the result in four-bit 0-3, add together two-bits 4-5 and 6-7 and put the result in four-bit 4-7 etc...

Example:

So if I have number 395 in binary 0000000110001011 (0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1)
After the first step I have:      0000000101000110 (0+0 0+0 0+0 0+1 1+0 0+0 1+0 1+1) = 00 00 00 01 01 00 01 10
In the second step I have:        0000000100010011 ( 00+00   00+01   01+00   01+10 ) = 0000 0001 0001 0011
In the fourth step I have:        0000000100000100 (   0000+0001       0001+0011   ) = 00000001 00000100
In the last step I have:          0000000000000101 (       00000001+00000100       )

which is equal to 5, which is the correct result

捂风挽笑 2024-10-02 17:41:37

我将使用预先计算的数组

uint8_t set_bits_in_byte_table[ 256 ];

该表中的第 i 个条目存储字节 i 中设置的位数,例如 set_bits_in_byte_table[ 100 ] = 3 因为十进制 100 (=0x64 = 0110-0100) 的二进制表示有 3 1 位。

然后我会尝试

size_t count_set_bits( uint32_t const x ) {
    size_t count = 0;
    uint8_t const * byte_ptr = (uint8_t const *) &x;
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    return count;
}

I would use a pre-computed array

uint8_t set_bits_in_byte_table[ 256 ];

The i-th entry in this table stores the number of set bits in byte i, e.g. set_bits_in_byte_table[ 100 ] = 3 since there are 3 1 bits in binary representation of decimal 100 (=0x64 = 0110-0100).

Then I would try

size_t count_set_bits( uint32_t const x ) {
    size_t count = 0;
    uint8_t const * byte_ptr = (uint8_t const *) &x;
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    count += set_bits_in_byte_table[ *byte_ptr++ ];
    return count;
}
想挽留 2024-10-02 17:41:37

这是答案的简单说明:

a b c d       0 a b c       0 b 0 d    
&             &             +
0 1 0 1       0 1 0 1       0 a 0 c
-------       -------       -------
0 b 0 d       0 a 0 c       a+b c+d

因此,我们正好有 2 位来存储 a + b 和 2 位来存储 c + d. a = 0, 1 等等,所以我们需要 2 位来存储它们的和。下一步,我们将使用 4 位来存储 2 位值之和等。

Here's a simple illustration to the answer:

a b c d       0 a b c       0 b 0 d    
&             &             +
0 1 0 1       0 1 0 1       0 a 0 c
-------       -------       -------
0 b 0 d       0 a 0 c       a+b c+d

So we have exactly 2 bits to store a + b and 2 bits to store c + d. a = 0, 1 etc., so 2 bits is what we need to store their sum. On the next step we'll have 4 bits to store sum of 2-bit values etc.

当爱已成负担 2024-10-02 17:41:37

此处有几个有趣的解决方案。

如果上面的解决方案太无聊,这里有一个免于条件测试或循环的 C 递归版本:

  int z(unsigned n, int count);
  int f(unsigned n, int count);

  int (*pf[2])(unsigned n, int count) = { z,f };

  int f(unsigned n, int count)
  {
     return (*pf[n > 0])(n >> 1, count+(n & 1));
  }

  int z(unsigned n, int count)
  {
     return count;
  }

  ...
  printf("%d\n", f(my_number, 0));

Several interesting solutions here.

If the solutions above are too boring, here is a C recursive version exempt of condition test or loop:

  int z(unsigned n, int count);
  int f(unsigned n, int count);

  int (*pf[2])(unsigned n, int count) = { z,f };

  int f(unsigned n, int count)
  {
     return (*pf[n > 0])(n >> 1, count+(n & 1));
  }

  int z(unsigned n, int count)
  {
     return count;
  }

  ...
  printf("%d\n", f(my_number, 0));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文