压缩浮点数据

Sza*_*lcs 40 compression floating-point time-series

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

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

我正在处理一些大型数据文件,这些文件是一系列相关的doubles,描述了时间的函数(即值是相关的).我通常不需要完全double精确但我可能需要更多float.

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

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

Fra*_*man 17

如果您想创建自己的简单算法,以下是一些想法:

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


xio*_*xox 5

HDF5 人员使用的一种技术是“混洗”,将 N 个浮点值的每个字节组合在一起。这更有可能为您提供重复的字节序列,使用 gzip 可以更好地压缩,例如.

我发现的第二种方法可以大大减少压缩的 gzip 数据的大小,首先将数据转换为float16(半精度)格式,然后再转换回 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
Run Code Online (Sandbox Code Playgroud)

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


Han*_*uys 5

由于您声明需要在'float'和'double'之间的精度:您可以将单精度和双精度float中的任意数量的最低有效位清零。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;
}
Run Code Online (Sandbox Code Playgroud)

还有一个在python / numpy中:

#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;
}
Run Code Online (Sandbox Code Playgroud)


pow*_*rbo 5

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

  • 对于 float 转置 4xN,对于 double + lz77 转置 8xN
    实现:TurboTranspose 中的浮点压缩
    另请参阅错误限制有损压缩

  • 预测器(例如有限上下文方法)+编码(例如“整数压缩”)。
    实现:TurboPFor 中的浮点压缩

  • 如果可能,将所有浮点数转换为整数(例如 1.63 -> 163),
    然后使用整数压缩
    实现:整数压缩

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


pri*_*tor 5

由于您要求使用现有工具,也许zfp可以解决问题。