【问题标题】:Can I use data types like bool to compress data while improving readability?我可以使用 bool 等数据类型来压缩数据,同时提高可读性吗?
【发布时间】:2014-09-18 19:14:30
【问题描述】:

我的官方问题是:“有没有一种干净的方法来使用数据类型来“编码和压缩”数据,而不是使用凌乱的位掩码。”希望是在压缩的情况下节省空间,我想使用本机数据类型、结构和数组来提高位掩码的可读性。我在汇编背景中精通位掩码,但我正在学习 C++ 和 OOP。我们可以通过使用单个位在 32 位寄存器中存储如此多的信息,我觉得我正试图回到那个低级环境,同时具有 C++ 代码的可读性。

我正在尝试节省一些空间,因为我需要处理大量资源。我仍在学习更多关于 c++ 如何处理 bool 数据类型的信息。我意识到内存存储在字节块中,而不是单个位中。我相信 bool 通常使用一个字节并且以某种方式被屏蔽。在我的脑海中,我可以在一个字节中使用 8 个 bool 值。

如果我在 C++ 中 malloc 一个包含 2 个 bool 元素的数组。它分配两个字节还是只分配一个?

示例:我们将使用 DNA 作为示例,因为它可以被编码为两位来表示 A、C、G 和 T。如果我创建一个包含两个 bool 的数组的结构,称为 DNA_Base,那么我将创建一个其中 20 个的数组。

struct DNA_Base{  bool Bit_1;  bool Bit_2; };
DNA_Base DNA_Sequence[7] = {false};
cout << sizeof(DNA_Base)<<sizeof(DNA_Sequence)<<endl;
//Yields a 2 and a 14. 
//I would like this to say 1 and 2.

在我的示例中,我还将展示 DNA 序列可以是 20 个碱基长的情况,这需要 40 位进行编码。 GATTACA最多只能占用2个字节?我想另一个问题是“如何让 C++ 以更易读的方式为我做位掩码”,或者我应该只创建自己的数据类型和类并使用类和运算符重载来实现位掩码。

【问题讨论】:

  • bool 实际上使用了一个完整的字节。除非您使用按位联合或std::bitset,否则您无法真正解决内存中的单个位。
  • 查看std::bitset 或名为std::vector&lt;bool&gt; 的错误,了解如何创建以部分字节存储元素的伪容器。
  • 它可能不是空间最优的,但使用enumenum class :char 来表示每个碱基可能是最易读和最有效的表示。通常应避免使用位域。

标签: c++ compression bigdata entropy dna-sequence


【解决方案1】:

不完全是你想要的,但你可以使用bitfield

struct DNA_Base
{
    unsigned char Bit_1 : 1;
    unsigned char Bit_2 : 1;
};
DNA_Base DNA_Sequence[7];

所以sizeof(DNA_Base) == 1sizeof(DNA_Sequence) == 7

所以你必须打包 DNA_Base 以避免丢失 padding 的位置,例如:

struct DNA_Base_4
{
    unsigned char base1 : 2; // may have value 0 1 2 or 3
    unsigned char base2 : 2;
    unsigned char base3 : 2;
    unsigned char base4 : 2;
};

所以sizeof(DNA_Base_4) == 1

std::bitset 是另一种选择,但您必须自己完成翻译工作。

【讨论】:

    【解决方案2】:

    一个布尔数组将是 N 个元素 x sizeof(bool)。

    如果您的目标是节省寄存器空间,请不要费心,因为对于相关处理器使用字长实际上比使用单个字节更有效,而且编译器会更喜欢使用一个字无论如何,因此在结构/类中,布尔值通常会扩展为 32 位或 64 位本机字。

    现在,如果您想在磁盘或 RAM 中节省空间,因为需要存储大量布尔值,请继续,但除非您实际打包结构,否则不会在所有情况下都节省空间,并且在某些架构上,打包也会对性能产生影响,因为 CPU 必须执行未对齐或逐字节访问。

    另一方面,位掩码(或位域)是高性能、高效且尽可能密集的,并且使用单个位操作。我会看看提供位字段的抽象数据类型之一。

    标准库有 bitset http://www.cplusplus.com/reference/bitset/bitset/,可以任意长。

    我确信 Boost 也有一些东西。

    【讨论】:

      【解决方案3】:

      除非您使用的是 4 位机器,否则最终结果将使用位运算。无论您是显式执行,让编译器通过位字段执行,还是使用位容器,都会有位操作。

      我建议如下:

      • 使用现有的压缩库。
      • 使用其他人最易读或理解的方法 比你自己。
      • 使用效率最高的方法(谈开发 时间)。
      • 使用将注入最少缺陷的方法。

      编辑 1:
      将每个方法写成一个单独的函数。
      告诉编译器为每个函数生成汇编语言。 比较每个函数的汇编语言。

      我相信它们会非常相似,以至于浪费时间讨论它们是不值得的。

      【讨论】:

        【解决方案4】:

        您不能直接对位进行操作,但可以将可用的最小单位视为多重数据存储,并定义

        enum class DNAx4 : uint8_t { 
           AAAA = 0x00, AAAC = 0x01, AAAG = 0x02, AAAT = 0x03,
           // .... And the rest of them
           AAAA = 0xFC, AAAC = 0xFD, AAAG = 0xFE, AAAT = 0xFF
        }
        

        我实际上会更进一步,创建一个结构 DNAx16 或 DNAx32 以有效地使用您机器上的原生字长。

        然后您可以在数据类型上定义函数,这些函数必须使用底层的位表示,但至少它允许您封装它并从这些原语构建更高级别的操作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多