存储一个十进制数字

时间:2017-07-08 11:58:28

标签: c++ digits

我有一个与大量小整数(实际上是十进制数字)有关的问题。存储此类数据的空间有效方式是什么?

使用std::bitset<4>存储一个十进制数字是个好主意吗?

3 个答案:

答案 0 :(得分:3)

根据 如何节省空间以及检索的效率,我看到了两种可能性:

  • 由于std::bitset<4>的向量(据我所知)存储在解压缩的设置中(每个位集存储在32或64位的存储器字中),您至少应该使用打包表示,如使用64位字来存储16位数字:

    store (if the digit was not stored before):
    block |= digit << 4 * index
    load:
    digit = (block >> 4 * index) & 0xF
    reset:
    block &= ~(0xF << 4 * index);
    

这些64位字(uint64_t)的向量以及一些访问方法应该易于实现。

  • 如果您的空间要求更加严格,您可以尝试使用分区和模数打包10位(最多1024位)的3位数,这样会节省很多时间。与64位字的对齐也要困难得多,所以我只推荐这个,如果你需要获得最后16%的改进,最多你可以获得每位数3.3位。

答案 1 :(得分:3)

如果你想要一个非常紧凑的方式,那么不,使用bitset<4>是一个坏主意,因为bitset<4>将使用至少一个字节,而不是4位。

我建议使用std::vector<std::uint32_t>

您可以在uint32_t中存储多个数字。两种常用方式:

  1. 每个数字使用4位,并使用位操作。这样,您可以在4个字节中存储8位数字。这里,set / get操作非常快。效率:4位/位
  2. 使用base 10编码。 uint32_t最大值为256 ^ 4-1,能够以4个字节存储9位数。效率:3.55bit /位。在这里,如果你需要设置/获取所有9位数,那么它几乎和以前的版本一样快(因为除以10将由优秀的编译器优化,CPU不会进行实际的划分)。如果您需要随机访问,则set / get将比以前的版本慢(您可以使用libdivide加快速度。)
  3. 如果您使用uint64_t代替uint32_t,那么您可以使用第一种方式存储16位数字(相同的4位/数字效率),使用第二种方式存储19位数字:3.36bit / digit efficieny ,这非常接近理论最小值:~3.3219bit / digit

答案 2 :(得分:1)

  

使用std :: bitset&lt; 4&gt;是否是个好主意。存储一个十进制数字?

是的,原则上这是一个好主意。它是众所周知的优化并称为BCD编码。

  

(实际上是十进制数字)。存储此类数据的空间有效方式是什么?

您可以使用占用字节的一个半字节来压缩十进制数字表示。此外,数学可能会应用于优化,而不是数字等的ASCII表示。

std::bitset<4>无法为压缩数据提供良好的服务 std::bitset<4>仍会占据一个完整的字节。

我能想到的另一种数据结构是位域

// Maybe #pragma pack(push(1))
struct TwoBCDDecimalDigits {
    uint8_t digit1 : 4;
    uint8_t digit2 : 4;
};
// Maybe #pragma pack(pop)

甚至还有一个库可用于将此格式转换为目标CPU架构支持的标准化数字格式:

我能想到的另一种方法是编写自己的类:

class BCDEncodedNumber {
    enum class Sign_t : char {
        plus = '+' ,
        minus = '-'
    };
    std::vector<uint8_t> doubleDigitsArray;
public:
    BCDEncodedNumber() = default;
    BCDEncodedNumber(int num) {
        AddDigits(num); // Implements math operation + against the
                        // current BCD representation stored in 
                        // doubleDigitsArray.
    }    
};