我有1024字节(8192位)的数组,大多数为零。
将设置0.01%到10%的位(随机,无模式)。
由于缺乏结构和相对较小的尺寸,如何压缩这些?
(我的第一个想法是存储设置位之间的距离。我需要每个距离13位,但在最坏情况下占用10%,这需要13 * 816 / 8
= 1326
个字节,这不是改善。)
这适用于超低带宽通信,因此每个字节都很重要。
答案 0 :(得分:3)
我已经深入研究了类似的问题,但我的设置要大得多(每组3000万个可能的值,每组有1到3千万个元素),因此它们从压缩中获得更多,压缩元数据无关紧要与数据的大小相比。我从来没有把事情压缩到小于uint16_t
的单位,所以如果你开始将13位值分成碎片,我写下面的内容可能不适用。感觉它应该起作用,但需要注意。
我发现的工作是采用几种依赖于我们所拥有的特定数据的策略。好消息是每个集合中的元素数量是一个非常好的指标,表明哪种压缩策略最适合特定集合。因此,您需要的所有元数据都是集合中元素的数量。在我的数据格式中,第一个也是唯一的元数据值(我将是非特定的,只是将其称为“值”,您可以按字节,16位值或13位值挤压,但是您觉得)是集合中元素的数量,其余的只是集合元素的编码。
策略是:
如果集合中的元素非常少,则不能比表示“1,4711,8140”的数组做得更好,因此在这种情况下,数据编码为:[3,1,4711] ,8140]
如果几乎所有元素都在集合中,您就可以跟踪不是的元素。例如[8190,17,42]。
如果大约有一半的元素在集合中,你几乎不能比位图做得更好,所以你得到[4000,{bitmap}],这是你的数据最终的唯一情况超过严格未压缩的时间。
如果设置了多于“少数”但少于“大约一半”的元素,我找到了另一种策略。将组中可能值的位除以一半。假设我们有2 ^ 16(它更容易描述,它可能适用于2 ^ 13)可能的值。这些值分为256个范围,每个范围具有256个可能的值。然后我们有一个256字节的数组,这些字节中的每一个都描述了每个范围内有多少个值(所以字节0告诉我们有多少元素是[0,255],字节1给我们[256,511]等),紧跟在数组之后这里的技巧是,虽然编码为数组(策略1)的集合中的每个元素都是2个字节,但在此方案中,每个元素只有1个字节+ 256个静态字节用于计数元素。这意味着只要我们在集合中有超过256个元素,就可以通过从策略1切换到4来节省空间。
策略4可以改进(如果您提到数据是随机的,可能毫无意义,但我的数据有时会有更多模式,所以它对我有用)。由于我们仍然需要在前一个编码中为每个元素使用8位,所以只要元素的子数组超过32个元素(256个字节),我们就可以将其存储为位图。这也是在4/5到3之间切换策略的一个很好的断点。如果这个策略中的所有数组都只是位图,那么我们应该只使用策略3(它比这更复杂,但策略之间的断点可以预先计算得很好准确地说,你每次都会选择最有效的策略。
我只是模糊地尝试在集合中的数字之间保存增量。快速实验表明它们并不比我上面提到的策略效率更高,具有不可预测的退化情况,但最重要的是,我使用的应用程序非常喜欢不需要对其数据进行反序列化,只需从磁盘直接使用它(MMAP)。