我想在内存中存储数十亿(10 ^ 9)的双精度浮点数并节省空间。这些值按数千个有序集合(它们是时间序列)进行分组,在一个集合中,我知道值之间的差异通常不大(与其绝对值相比)。而且,彼此越接近,差异相对较小的概率就越高。
完美契合将是一种delta编码,它只存储每个值与其前一个值的差异。但是,我想随机访问数据的子集,所以我不能依赖于按顺序完成整个集合。因此,我将deltas用于一个集合范围的基线,产生增量,我预计它将在绝对值的10%到50%之间(大部分时间)。
我考虑过以下方法:
有没有标准方法可以做到这一点?我上面的方法可能有什么问题?您自己看过或使用过哪些其他解决方案?
答案 0 :(得分:9)
很少有双精度数的所有位都有意义。
如果您有数十亿个值是某些测量值的结果,请找到测量设备的校准和误差。量化值,以便只使用有意义的位。
通常,您会发现只需要16位的实际动态范围。您可以将所有这些压缩为保留所有原始输入的“短”数组。
使用简单的“Z-score技术”,其中每个值实际上都是标准偏差的有符号部分。
因此,平均值为 m 且标准差 s 的样本序列将转换为一堆Z得分。正常的Z-score转换使用double,但您应该使用该double的定点版本。 s / 1000或 s / 16384或者只保留数据实际精度的东西,而不是最后的噪声位。
for u in samples:
z = int( 16384*(u-m)/s )
for z in scaled_samples:
u = s*(z/16384.0)+m
您的Z分数保留了与原始样本的统计关系的愉快易用性。
假设您使用带符号的16位Z分数。你有+/- 32,768。将此缩放16,384,您的Z分数的有效分辨率为0.000061十进制。
如果你使用签名的24但Z分数,你有+/- 800万。按比例缩放4,194,304,你的分辨率为0.00000024。
我严重怀疑你的测量设备是否准确。此外,作为滤波器,校准或降噪的一部分而进行的任何算术可能由于在算术期间引入的噪声比特而减小有效范围。一个经过深思熟虑的除法运算符可以使你的许多小数位数不过是噪音。
答案 1 :(得分:4)
无论你选择哪种压缩方案,你都可以通过压缩成固定大小的块并在每个块前面加上一个包含解压缩所需数据的标头(例如for)来解决需要能够执行任意搜索的问题。对于delta编码方案,该块将包含以某种方式加入的增量,利用它们的小幅度使它们占用更少的空间,例如指数/尾数的位数更少,转换为定点值,霍夫曼编码等;以及标题一个未压缩的样本);寻求然后成为廉价选择适当的块,然后解压缩它的问题。
如果压缩比如此变化以至于浪费了大量空间来填充压缩数据以产生固定大小的块,则可以构建压缩数据的偏移目录,并且在其中记录解压缩所需的状态。 p>
答案 2 :(得分:3)
如果你知道一组双打具有相同的指数,你可以存储指数一次,并且只存储每个值的尾数。