最有效的位格式表示小的无符号整数

时间:2016-01-03 23:11:25

标签: algorithm

我必须处理大量小数的序列,大约一百万,我必须在4KB中尽可能多地(更多更好)。显然,放置所有这些空间的空间太小了。此外,虽然这是一个特定的场景,但我会尽可能地回答一般问题。

这些数字不遵循任何模式,但这是一个小脚本对其分布的说法:

407037   times 1
165000   times 2
85389    times 3
52257    times 4
34749    times 5
23567    times 6
15892    times 7
11183    times 8
7636     times 9
5402     times 10
3851     times 11
2664     times 12
2023     times 13
1547     times 14
1113     times 15

... many more lines ...

1    times 62
62是我拥有的最大数字,所以让我们设置我们关心的最大数量为64.如果方法很容易适应更大的最大数量,那就更好了。

以下是数字的示例:

20
1
1
1
13
1
5
1
15
1
3
4
3
2
2

一种天真的方法就是每个数字使用6位,但我认为我们可以做得更好。

编辑:在评论中讨论后添加一些信息。

我还在微处理器上有2KB的ram和十几个周期来解码每个数字。我需要按顺序从第一个数字中存储尽可能多的数字。

编辑:看看graybeard的评论和我的后续行动。

4 个答案:

答案 0 :(得分:3)

执行此操作的正确方法是RangecodingHuffmanShannon-Fano,您可以通过网络在任何数字通信博客中看到,所以我是不完全解释你这些。

我可以建议你一个自定义方法,这非常简单,你可以将它与其他方法进行比较,如果你可以使用它来存储更​​多的数字。

我发现您的脚本中没有0's。因此,只需将每个数字减1(解码时,将1加到解码结果中)。使用4或7位编码数字。所有高达8的数字都可以用3位表示。如果数字为n <= 8,则将第1位设置为0,接下来的3位可以表示该数字。否则,如果数字为n > 8,则将第1位设置为1,并将数字表示为6位。

虽然在HuffmanShannon-Fano,但很少有表示可以超过20 bits

答案 1 :(得分:1)

为了提供正确答案,需要知道 - 解码器大小是否也有限,或者解码大小没有限制? 如果解码器没有限制(仅限数据),建议您使用rangecoderHuffman coding。 Rangecoder具有更好的压缩性,但具有广泛的算术运算用途。

但是,两个解码器都使用内存来代码和统计表。所以,或许,更好的答案可以创建更简单的东西(自定义压缩器),但代码简单紧凑,没有任何表格。因为简单,代码紧凑,我可以提出run-1算法。这个算法对你的数据(范围编码器或霍夫曼更好)效率不高,但是没有任何表格的平凡紧凑型解码器。

Idea - 序列可以包含零个或多个bit_1,并使用bit_0作为符号分隔符。例如,如果我们想用run-1编码序列:

1, 1, 2, 1, 5

会有位序列:

0-0-10-0-11110

在那里,你只需要计算顺序bit_1的数量,加1,并将返回值作为解码数。

答案 2 :(得分:1)

可能通过结合游程编码尝试稍微好于直接的Huffman。

如果计算连续相同的元素,则可以将序列重写为(值,计数)对。每个这样的对都有一定的概率,你可以在这些上使用霍夫曼编码。 (我不是要分别编码值和计数,而是将对作为一个整体)。

您的样本产量

let numbersTest = resultTitles[indexPath.row]
        if let number = Int(numbersTest){
            print(number)//contains onlyy number
        }else{
            print("notnumber")//Not number
        }

单身人士(实际上)将像以前一样进行编码,并且有更多机会压缩更长的跑步。

您可以限制支持的最大数量;如果实际计数超过限制,插入几对没什么大不了的。

第一步是计算计数值的直方图,以查看是否有足够的重复值来进行此方法。

或者,您可以尝试对增量进行霍夫曼编码(连续值之间的符号差异)。如果有很多重复,则频率为0将更高,增加熵。显然,增量的运行长度编码也是可能的。

答案 3 :(得分:1)

我选择了您列出的发行版,并尝试了指数拟合。结果非常好:

enter image description here

更重要的是,拟合度恰好接近p(x) ~= 2^-x。这表明一个非常简单的编码,称为&#34;一元编码&#34;:编码数字k,输出k-1零,后跟1。如果您的数字完全符合{{ 1}}分布,这将给你一个2位的预期代码长度。由于你的数字看起来比那个更重(否则很难看到只有一百万个数字的62),你就不会实现这一目标。考虑到编码的简单性和解码的简易性(十二个周期应该足够),你应该考虑尝试一下。

您还可以查看其他通用代码,例如Elias Delta。 Golomb编码是最佳的,但解码它是一个涉及的过程。