String 为什么liblzma无法压缩任何随机字符串?

String 为什么liblzma无法压缩任何随机字符串?,string,random,compression,complexity-theory,String,Random,Compression,Complexity Theory,我正在使用ruby绑定,RubyXZ random_string = SecureRandom.random_bytes(100) compressed_string = XZ.compress(random_string, compression_level = 9, check = :none, extreme = true) compressed_string.size # => always 148 我已经在不同长度的弦上测试了一万次了 我知道至少有一半的字符串是1-不可压缩的(

我正在使用ruby绑定,
RubyXZ

random_string = SecureRandom.random_bytes(100)
compressed_string = XZ.compress(random_string, compression_level = 9, check = :none, extreme = true)
compressed_string.size # => always 148
我已经在不同长度的弦上测试了一万次了

我知道至少有一半的字符串是1-不可压缩的(不能压缩超过1位),3/4的字符串是2-不可压缩的,等等(这是从一个计数参数得出的)。显然,这并没有说明可压缩字符串数的下限,但一定会有一些,不是吗?

解释 有几个原因:

  • liblzma在不处于原始模式时,会添加一个描述字典大小的标题和一些其他设置。这是其规模不断扩大的原因之一

  • LZMA和许多其他压缩器一样,使用范围编码器以所需的最少比特数对字典压缩(本质上是LZ77的一个糟糕版本)的输出进行编码。所以在比特流的末尾,最后的比特被填充成一个完整的字节

  • 您正在压缩随机噪声,正如您所注意到的,这是很难压缩的。范围编码器试图找到最少的比特数来对字典压缩轮输出的符号进行编码。所以在这种情况下,会有很多符号。如果LZMA发现了一个(或两个)重复出现的模式,那么它最终可能只从输出中保存了一两位。正如第2点所解释的,您无法在字节级别上观察到

  • 实验 一些观察头顶的小实验

    lzma处于原始模式的空文件: 它至少需要一个或两个位来表示它到达了流的末尾,这被填充为一个字节

    1k文件中填充了零 相当不错,但从复杂性理论来看,仍然可能是几个字节到多个字节(1000x'\0'将是最佳编码)

    所有位为1的1k文件 有趣的是,xz对它的压缩比全零稍微差一点。最有可能与LZMA字典在比特级别上工作这一事实有关(这是LZMA的一个新颖想法)

    1k随机文件: 所以比输入多4个字节,还是不错的

    1000次运行1k随机文件: 所以每次都需要1028字节

    $ dd if=/dev/urandom bs=1k count=0 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
           1     
    
    $ dd if=/dev/zero bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
          19
    
    $ dd if=/dev/zero bs=1k count=1 2>/dev/null | sed 's/\x00/\xFF/g'| xz -9 -e --format=raw -c 2>/dev/null | wc -c
          21
    
    $ dd if=/dev/urandom bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
        1028
    
    $ for i in {1..1000}; do dd if=/dev/urandom bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c; done | sort | uniq -c
    1000     1028