【问题标题】:How to access range of bits in a bitset?如何访问位集中的位范围?
【发布时间】:2019-06-18 21:50:14
【问题描述】:

我有一个非常大的位集,比如 100 亿位。

我想做的是把它写到一个文件中。但是使用.to_string() 实际上会冻结我的计算机。

我想做的是遍历位并一次取 64 位,将其转换为 uint64,然后将其写入文件。

但是我不知道如何访问不同范围的位集。我该怎么做?我是 C++ 新手,不知道如何访问底层的 bitset::reference,所以请提供一个示例作为答案。

我尝试使用指针,但没有达到我的预期。这是我目前正在尝试的一个示例。

#include <iostream>
#include <bitset>
#include <cstring>
using namespace std;

int main()
{
    bitset<50> bit_array(302332342342342323);
    cout<<bit_array << "\n";
    bitset<50>* p;
    p = &bit_array;
    p++;
    int some_int;
    memcpy(&some_int, p , 2);
    cout << &bit_array << "\n";
    cout << &p << "\n";
    cout << some_int << "\n";

    return 0;
}

输出

10000110011010100111011101011011010101011010110011
0x7ffe8aa2b090                                                                                                                          
0x7ffe8aa2b098
17736

最后一个数字似乎在每次运行时都会发生变化,这不是我所期望的。

【问题讨论】:

  • some_int 未初始化。然后你复制两个字节给它,让它的其余部分处于未初始化状态。
  • 您的代码中有错误,但关于问题本身,我想不出任何解决方案,但 test(pos) 每个位在位置,将 64 位打包到 uint64_t 并将这个 uint64_t 写入文件 - 手动,乏味和不好
  • 您可能想看看bitset2。它允许访问底层数组。

标签: c++ bitset std-bitset


【解决方案1】:

程序中有几个错误。 bitset&lt;50&gt; 可以容纳的最大值是1125899906842623,这比程序中初始化的bit_array 要小得多。

some_int 必须定义为 unsigned long 并验证 unsigned long 在您的平台上是否有 64 位。

之后,在循环中测试bit_array 的每一位,然后执行适当的按位(或和移位)运算并将结果存储到some_int

std::size_t start_bit = 0;
std::size_t end_bit = 64;
for (std::size_t i = start_bit; i < end_bit; i++) {
    if (bit_array[i])
       some_int |= mask;
    mask <<= 1;
}

您可以在浏览大型位集时适当地更改start_bitend_bit 的值。

DEMO

【讨论】:

  • 对“错误”感到抱歉。我使用 50 编写了示例,因为我懒得写一个大于 1500 亿位的非常大的位集,但基本上使用 50 和一个 int 来说明我试图将一系列字节从较大的数据大小变为较小的问题使用位集的数据大小(int)。本质上,该示例的解决方案将解决我的问题。也就是说,我希望一次获得 64 位的副本,因为这对我来说最有意义
【解决方案2】:

要访问bitset 的范围,您应该查看提供的接口。缺少 bitset::data() 之类的内容表明您应该尝试直接访问基础数据。这样做,即使它看起来有效,也是脆弱的、骇人听闻的,并且可能是某种未定义的行为。

我看到将大量 bitset 转换为更易于管理的部分的两种可能性。一种相当直接的方法是逐位检查并将它们收集到某种整数中(或者如果您不那么关心文件,则将它们直接写入文件'0''1'尺寸)。看起来 P.W 已经为此提供了代码,所以我现在将跳过一个示例。

第二种可能性是使用位运算符和to_ullong()。这种方法的缺点是它名义上使用辅助存储空间,特别是两个与原始大小相同的附加位集。不过,我说“名义上”,因为编译器可能足够聪明,可以将它们优化掉。可能。也许不吧。而且您正在处理每个超过 1 GB 的大小。实际上,一点一点的方法可能是要走的路,但我认为这个例子在理论上很有趣。

#include <iostream>
#include <iomanip>
#include <bitset>
#include <cstdint>
using namespace std;

constexpr size_t FULL_SIZE = 120; // Some large number
constexpr size_t CHUNK_SIZE = 64; // Currently the mask assumes 64. Otherwise, this code just
                                  // assumes CHUNK_SIZE is nonzero and at most the number of
                                  // bits in long long (which is at least 64).

int main()
{
    // Generate some large bitset. This is just test data, so don't read too much into this.
    bitset<FULL_SIZE> bit_array(302332342342342323);
    bit_array |= bit_array << (FULL_SIZE/2);
    cout << "Source: " << bit_array << "\n";

    // The mask avoids overflow in to_ullong().
    // The mask should be have exactly its CHUNK_SIZE low-order bits set.
    // As long as we're dealing with 64-bit chunks, there's a handy constant to handle this.
    constexpr bitset<FULL_SIZE> mask64(UINT64_MAX);
    cout << "Mask:   " << mask64 << "\n";

    // Extract chunks.
    const size_t num_chunks = (FULL_SIZE + CHUNK_SIZE - 1)/CHUNK_SIZE; // Round up.
    for ( size_t i = 0; i < num_chunks; ++i ) {
        // Extract the next CHUNK_SIZE bits, then convert to an integer.
        const bitset<FULL_SIZE> chunk_set{(bit_array >> (CHUNK_SIZE * i)) & mask64};
        unsigned long long chunk_val = chunk_set.to_ullong();
        // NOTE: as long as CHUNK_SIZE <= 64, chunk_val can be converted safely to the desired uint64_t.
        cout << "Chunk " << dec << i << ": 0x" << hex << setfill('0') << setw(16) << chunk_val << "\n";
    }

    return 0;
}

输出:

Source: 010000110010000110011010100111011101011011010101011010110011010000110010000110011010100111011101011011010101011010110011
Mask:   000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111
Chunk 0: 0x343219a9dd6d56b3
Chunk 1: 0x0043219a9dd6d56b

【讨论】:

  • 感谢您的回复。遗憾的是我们无法访问底层位,因为这似乎是最明显的事情。
猜你喜欢
  • 2013-07-25
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 2023-04-08
  • 2015-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多