压缩浮点数据

时间:2011-12-25 17:18:49

标签: compression floating-point time-series

是否有任何可以应用于浮点时间序列数据的无损压缩方法,并且会显着优于将数据作为二进制文件写入文件并通过gzip运行?

降低精度可能是可以接受的,但它必须以受控方式发生(即我必须能够设置必须保留多少位数的界限)

我正在处理一些大型数据文件,这些文件是一系列相关double s,描述时间函数(即值是相关的)。我通常不需要完整的double精度,但我可能需要超过float

由于图像/音频有专门的无损方法,我想知道这种情况是否有专门的存在。

澄清:我正在寻找现有的实用工具,而不是描述如何实现这样的东西的论文。在速度上与gzip相当的东西会很棒。

7 个答案:

答案 0 :(得分:22)

答案 1 :(得分:17)

如果您想创建自己的简单算法,请参考以下内容:

  • 使用当前值的xor和先前的值来获取描述差异的一组位。
  • 将这个差异分为两部分:一部分是“尾数位”,一部分是“指数位”。
  • 使用可变长度编码(每个值的不同位数/字节数)或您选择的任何压缩方法来保存这些差异。你可能会为mantissas和exponents使用单独的流,因为mantissas有更多的位来压缩。
  • 如果您在两个不同的时间值流源之间交替,这可能无法正常工作。因此,您可能必须将每个源压缩为单独的流或块。
  • 要丢失精度,可以从尾数中删除最低有效位或字节,同时保持指数不变。

答案 2 :(得分:4)

因为你说你需要一个精确度介于' float'和' double':您可以将单精度和双精度浮点数中的任意数量的最低有效位清零。 IEEE-754浮点数的二进制大致表示为seeefffffffff,代表值

符号* 1.fffffff * 2 ^(EEE)。

您可以将最不重要的分数(f)位清零。对于单精度(32位)浮点数,有23个小数位,你可以将其归零至22个。对于双精度(64位),它是52,最多为51.(如果你将所有位置零,然后特殊值NaN和+/- inf将丢失。)

特别是如果数据表示十进制值,例如1.2345,这将有助于数据压缩。这是因为1.2345不能完全表示为二进制浮点值,而是0x3ff3c083126e978d,这对数据压缩不友好。截断最低有效24位将导致0x3ff3c08312000000,其仍然精确到大约9个十进制数字(在此示例中,差异为1.6e-9)。

如果你对原始数据执行此操作,然后存储后续数字之间的差异,那么如果原始数据变化缓慢,它将更加适合压缩(通过gzip)。

这是C:

中的一个例子
#include <inttypes.h>

double double_trunc(double x, int zerobits)
{
  // mask is e.g. 0xffffffffffff0000 for zerobits==16
  uint64_t mask = -(1LL << zerobits);  
  uint64_t floatbits = (*((uint64_t*)(&x)));
  floatbits &= mask;
  x = * ((double*) (&floatbits));
  return x;
}

一个在python / numpy中:

import numpy as np

def float_trunc(a, zerobits):
    """Set the least significant <zerobits> bits to zero in a numpy float32 or float64 array.
    Do this in-place. Also return the updated array.
    Maximum values of 'nzero': 51 for float64; 22 for float32.
    """

at = a.dtype
assert at == np.float64 or at == np.float32 or at == np.complex128 or at == np.complex64
if at == np.float64 or at == np.complex128:
    assert nzero <= 51
    mask = 0xffffffffffffffff - (1 << nzero) + 1
    bits = a.view(np.uint64)
    bits &= mask
elif at == np.float32 or at == np.complex64:
    assert nzero <= 22
    mask = 0xffffffff - (1 << nzero) + 1
    bits = a.view(np.uint32)
    bits &= mask

return a

答案 3 :(得分:3)

可用于浮点压缩的可能方法:

您可以使用适用于Linux和Windows的icapp工具,使用您的数据测试所有这些方法。

答案 4 :(得分:3)

由于您要求使用现有工具,因此zfp可能会做到这一点。

答案 5 :(得分:2)

HDF5用户使用的一种技术是“混洗”,您可以将每个字节分组为N个浮点值。这更有可能为您提供重复的字节序列,使用gzip for example可以更好地压缩。

我发现的第二种方法可以大大减少压缩gzip压缩数据的大小,首先将数据转换为float16 (half-precision) format,然后再转换回float32。这会在输出流中产生大量零,这可以在压缩后将文件大小缩小约40-60%。一个微妙之处是最大float16值相当低,因此您可能希望首先缩放数据,例如在python中

import numpy as np
import math

input = np.array(...)

# format can only hold 65504 maximum, so we scale input data
log2max = int(math.log(np.nanmax(input), 2))
scale = 2**(log2max - 14)
scaled = input * (1./scale)

# do the conversion to float16
temp_float16 = np.array(scaled, dtype=np.float16)
# convert back again and rescale
output = np.array(temp_float16, dtype=np.float32) * scale

一些测试表明,某些数据的输入和输出之间的平均绝对分数差值约为0.00019,最大值为0.00048。这符合尾数的2 ** 11精度。

答案 6 :(得分:1)

您可以使用Holt的指数平滑算法(这是基于预测的压缩算法)。最初为数据分配一些权重并预测下一个值。如果两个数据相同,则通过执行异或操作在MSB中产生许多零