给定std::bitset<64> bits
设置任意位数且位位置X
(0-63)
在X位置或更低位置计数位的最有效方法是什么?如果未设置X位,则返回0
注意:如果设置该位,则返回始终至少为1
蛮力方式很慢:
int countupto(std::bitset<64> bits, int X)
{
if (!bits[X]) return 0;
int total=1;
for (int i=0; i < X; ++i)
{
total+=bits[i];
}
return total;
}
count()
的{{1}}方法将为您提供所有位的bitset
,但popcount
不支持范围
注意:这不是How to count the number of set bits in a 32-bit integer?的重复,因为它询问所有位而不是范围0到X
答案 0 :(得分:10)
我的立即反应是测试指定的位,并立即返回0清除。
如果超过该值,则使用该位(以及不太重要的位)设置位掩码,并使用原始输入创建and
位掩码。然后使用count()
成员函数来获取结果中设置的位数。
至于创建蒙版:你可以向左移动1个位置,然后减去1。
答案 1 :(得分:5)
假设unsigned long
或unsigned long long
足够容纳64位,您可以调用bits.to_unlong()
(或bits.to_ullong()
)来获取整数位掩码数据,掩码关闭X((1 << X) - 1
)以上的位,然后计算您链接到的问题的答案中给出的那些位。
答案 2 :(得分:5)
在它下面的位上转换位和掩码很容易,所以这样的东西应该有效:
int popcnt(bitset<64> bs, int x) {
// Early out when bit not set
if (!bs[x]) return 0;
// Otherwise, make mask from `x`, mask and count bits
return (bs & bitset<64>((1UL << x) - 1)).count() + 1;
}
这里的假设是bitset::count
有效实施(使用popcnt
内在函数或有效回退);这不能保证,但STL人员倾向于优化这类事情。
答案 3 :(得分:1)
我编辑过一个我之前看过的问题,检查一个数字中是否设置了奇数或偶数位。它适用于C,但要将它按到C ++中并不是很难。解决方案的关键在于while循环中的内容。在纸上试一试,了解它如何挑出LSB,然后将其从x中删除。其余的代码是直截了当的。代码在O(n)中运行,其中n是x中的设置位数。这比线性时间好得多,我以为只有在第一次看到这个问题时才有可能。
#include <stdio.h>
int
count(long x, int pos)
{
/* if bit at location pos is not set, return 0 */
if (!((x >> pos) & 1))
{
return 0;
}
/* prepare x by removing set bits after position pos */
long tmp = x;
tmp = tmp >> (pos + 1);
tmp = tmp << (pos + 1);
x ^= tmp;
/* increment count every time the first set bit of x is removed (from the right) */
int y;
int count = 0;
while (x != 0)
{
y = x & ~(x - 1);
x ^= y;
count++;
}
return count;
}
int
main(void)
{
/* run tests */
long num = 0b1010111;
printf("%d\n", count(num, 0)); /* prints: 1 */
printf("%d\n", count(num, 1)); /* prints: 2 */
printf("%d\n", count(num, 2)); /* prints: 3 */
printf("%d\n", count(num, 3)); /* prints: 0 */
printf("%d\n", count(num, 4)); /* prints: 4 */
printf("%d\n", count(num, 5)); /* prints: 0 */
printf("%d\n", count(num, 6)); /* prints: 5 */
}