【问题标题】:How to loop bit by bit over a long long in C++如何在 C++ 中逐位循环 long long
【发布时间】:2013-11-18 18:16:24
【问题描述】:

如果我在 c++ 中有long long x;,我如何遍历数字中的每个位以检查它是零还是 1?

我想计算位中的个数。

【问题讨论】:

标签: c++ bit long-long


【解决方案1】:

你需要使用移位>>操作符:

unsigned long long x = static_cast<unsigned long long>(your_value);
//unsigned long long fix for issue pointed out by @Zac Howland in comments
unsigned int count = 0;//number of 1 bits
while (x != 0)
{
    unsigned long long bit = x & 1;
    if( bit == 1 )
    {
        count ++;//...
    }
    else //zero
    {
        //...
    }
    x >>= 1;
}

还有其他方法可以通过各种方式执行此操作,您可以找到它们here (along with other stuff)

【讨论】:

  • 如果x 是否定的,您可能会遇到的一个问题(实现定义)。一些实现通过保持负数来实现负数的右移,所以你永远不会得到x == 0
  • @Zac Howland 那,我没想到
  • 不需要做移位操作。
  • @VladfromMoscow 如果您所做的只是计算位,那么实际上根本不需要循环......
  • 如果需要统计最大连续位数集怎么办?这在这种情况下很有用。
【解决方案2】:

你不需要做移位操作。:)

size_t count = 0;

for ( long long v = x; v; v &= v - 1 ) ++count;

【讨论】:

  • 你意识到v &amp;= v - 1 基本上是一个右移,对吧? :-P
  • 不,这不是因为左边的位没有被移动并被 zeo 填充。
  • 当然可以。它给您带来的是默认的 0 移位。也就是说,如果你有1111,那么每次迭代基本上都和&lt;&lt; 1一样。如果你有1001,第一次迭代基本上是&lt;&lt; 3。它仍然是有效的右移 - 只是由定位决定的可变数量的移位。不过,对于位计数,您完全可以不使用循环。
【解决方案3】:
const unsigned int BITCOUNT = sizeof(long long) * CHAR_BIT - 1;
// or
const unsigned int BITCOUNT = sizeof(unsigned long long) * CHAR_BIT;

for (unsigned int i = 0; i < BITCOUNT; ++i)
{
    unsigned int test_bit = 1LL << i;
    if (value & test_bit)
    {
        // do something
    }
}

如果只需要位数,可以使用 SWAR 算法:

unsigned int bit_count(unsigned long long i)
{
    i = i - ((i >> 1) & 0x5555555555555555);
    i = (i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F0F0F0F0F) * 0x0101010101010101) >> 56;
}

【讨论】:

  • 为什么是 8? :P (/pedantic - 它应该是CHAR_BIT)
【解决方案4】:

以下程序显示了用于循环一个字节的过程

#include <iostream>

int main()
{
    std::uint_fast8_t flags{ 0b10011000 };

    for (int i = 128; i >= 1; i /= 2)
    {
        if (flags & i)
            std::cout << '1';
        else
            std::cout << '0';
    }

    std::cout << '\n';
    return 0;
}

这个打印:10011000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 2010-11-30
    • 2017-02-08
    • 1970-01-01
    相关资源
    最近更新 更多