Версия 2
от 20.09.2006
В данном документе рассматриваются проблемы кодирование бинарных данных в текст на примере, как широко применяемых Hex и base64 кодеров, так и нестандартных. Основное внимание уделено таким аспектам как оптимальность кодирования и искажение статистических характеристик кодером. Проведен анализ совместного использования RLE и LZ алгоритмов сжатия. Предложен вариант статистического кодера бинарных данных в текст с кодами переменной длины и встроенным RLE.
Кодирование в шестнадцатеричной системе применяется достаточно широко для хранения бинарных данных в тексте. Алфавит кодера можно назвать общепринятым. Алгоритмы кодирования и декодирования очень просты и, фактически, оперируют данными на уровне байта, как единицы данных, используя для представления 2 символа. Таким образом, в закодированном виде получается 100% прирост объема данных, что собственно и является основным недостатком.
Кодирование в алфавите из 64 символов позволяет уменьшить прирост объема данных до 33%. Достигается это тем, что данные кодируются на битовом уровне (6 бит на выходной символ), при этом каждые 3 байта данных кодируются 4 символами. Существует несколько алфавитов для такого кодера, например:
b64_MIME = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
b64_UU = ' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_';
b64_XX = '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
Кроме того, иногда принято выравнивать закодированные данные, на границу 4х символов специальными символами-заполнителями (обычно символ =).
Рассмотрим задачу сжатия закодированных в текст данных и более общую задачу оптимального кодирования бинарных данных передаваемых в тексте. Понятно, что кодер в текст с очень незначительной вероятностью может улучшить степень последующего сжатия данных. Можно постулировать, что в любом случае выгоднее произвести сначала сжатие бинарных данных и только потом кодирование в текст. Для экономии места в этом случае следует пользоваться base64 кодером (потенциально можно использовать, по аналогии с арифметическим кодированием, кодер с алфавитом, количество символов которого не равно 2^n).
Однако, по многим причинам, в текст часто кодируют не сжатые, а исходные данные. Кроме того, на разных этапах обработки могут быть поставлены существенно разные требования к алгоритмам сжатия: так, в программу может встроен достаточно простой и быстрый алгоритм, который обеспечит скорость работы с данными и посредственное сжатие, но тогда пакет полученный по схеме данные > архив > текст будет невозможно сжать внешними, возможно, более оптимальными по степени сжатия алгоритмами.
Если хранить в пакете несжатые данные, то следует рассмотреть вопросы оптимальности кодов. Так Hex кодер увеличит объем на 100%, что может оказаться неприемлемым в случае транспортировки и хранения данных в несжатом виде. Base64 кодер увеличит объем на 33% и с этой точки зрения выглядит лучше. Если применить к закодированным и оригинальным данным типовой LZ архиватор, то, как правило, можно наблюдать следующее.
Улучшение результатов сжатия Base64 кода путем манипуляций с параметрами LZ компрессора представляется гораздо более сложной задачей. Однако увеличение размера словаря, длины цепочки и глубины поиска потенциально могут несколько улучшить результат.
Таким образом, можно постулировать, что эффективно сжиматься типовыми алгоритмами будет код, построенный из исходных данных так, что выполняются 2 следующих требования.
Рассмотрим статистический 2х проходный кодер (разработан А. Серовым) имеющий 130-символьный алфавит. В первый проход кодер считает элементарную статистику: а именно, количество байтов с установленным старшим битом. Эта статистика позволит оптимизировать кодирование статистически смещенных данных (например с большим количеством 0, текста и тп). В зависимости от подсчитанного значения выбираются байтоые значения, которые будут кодироваться одним символом (7 бит), либо это будут байты со значением более 127, либо наоборот. Другая половина в любом случае кодируется исходя из 2х символов на байт (1 служебный + 1 кодовый). Для того, чтобы декодер смог определить, какая "половина" байта кодируется 1 символом, первым символом в пакете может быть еще один служебный символ, указывающий на "короткое" кодирование "верхней половины" байта. Таким образом, во время кодирования (второй проход) используются 128 кодовых символов и 2 служебных: для указания статистики декодеру и для 2х символьного кодирования байта.
Легко видеть, что кодер обеспечивает объем пакета в пределах 100%..150% от исходных данных в зависимости от статистических характеристик. Кодер удовлетворяет второму требованию по эффективному сжатию указанному выше - байтовые границы не нарушаются и кодирование однозначное. И теоретически и практически такой код будет лучше Hex на любых данных как с точки зрения объема пакета, так и с точки зрения сжимаемости (т. к. цепочки могут совпадать или быть близки по длине к исходным). См. данные эксперимента 1.
Из недостатков кодера можно назвать следующие.
Из названных недостатков наиболее трудно устранимым представляется последний.
Избавиться от двух проходов по данным в статистическом кодере можно только путем
применения адаптивных методик, но это усложнит кодер и приведет к неоднозначному
кодированию символов входных данных, что снизит эффективность последующего
сжатия. Фактически, данный недостаток приводит к увеличению времени кодирования
и невозможности "поточного" кодирования данных недоступных кодеру полностью на
момент начала кодирования.
Можно сконструировать аналогичный статистический кодер с переменной длиной
кодов, который будет лишен ряда указанных выше недостатков и эффективнее
использовать статистику данных, а так же учитывать возможность последующего
сжатия. Ниже представлены направления таких улучшений.
Такой кодер обеспечит объем пакета в пределах N..175%+43символа (не более 133% если кодер будет выбирать между статистическими кодами и MIME на основании статистики данных). При использовании RLE нижняя граница N не фиксирована и может быть существенно меньше 100%. Ориентирован кодер на крупные (однако, следует помнить, что кодер двухпроходный) объемы данных с "хорошей" статистикой. Алфавит такого кодера может быть больше 64 символов и меньше (но тогда придется вводить дополнительные служебные символы). Выбор длины алфавита будет оказывать влияние на максимальный объем кода (чем длиннее, тем меньше). Алгоритм кодера, разумеется, сложнее рассмотренных ранее, однако дополнительные издержки на сортировки и прочее являются константой по времени.
Алгоритм RLE в простейшем случае использует кодирование длинных повторов одного и того же значения байта при помощи указания значения байта и количества повторений, например, по такой схеме:
Одним из практических применений RLE является сжатие изображений, особенно "деловой" графики, факсимильных и других, для которых характерны "заливки" одним цветом.
Рассмотрим влияние предварительного RLE кодирования данных на эффективность LZ сжатия.
RLE алгоритм легко встроить в статистический кодер бинарных данных в текст - достаточно введения еще одного служебного символа-флага, который будет указывать на то, что необходимо продублировать предыдущий закодированный байт, в количестве, определяемом следующим за флагом кодовым символом. При этом в дублировании самого символа- флага нет необходимости, т. к. он является дополнительным и не может встретиться в другом контексте. Соответственно, длина повтора, кодируемого одной конструкцией, меньше, чем длина повтора в бинарном варианте RLE, т. к. количество кодовых символов меньше.
Рассмотрим практическую реализацию статистического кодера, базирующуюся на рассуждениях приведенных выше. Условно будем называть этот кодер S64. Он обладает следующими особенностями.
В данном эксперименте производилось кодирование данных различными кодерами и последующее сжатие полученного кода алгоритмами ZIP и LZH. В качестве тестового набора использовался известный пакет Calgary Compression Corpus, дополненный файлом zip.dat с высокой энтропией (ZIP архив файла book1.dat). Данные по каждому файлу представлены в виде трех строк: первая относится к несжатым данным, вторая - к данным, сжатым ZIP, третья к данным, сжатым LZH. В столбцах содержатся следующие данные:
Data file | Hex | MIME | V7 | S64 wo RLE | S64 + RLE | RLE binary |
---|---|---|---|---|---|---|
bib.dat (111261) | .hex (222522) (2,00) | .b64 (148348) (1,33) | .v7 (111261) (1,00) | .s64 (111876) (1,01) | .s64r (111876) (1,01) | .rle (111262) (1,00) |
zip (35316) (0,32) | .zip (43956) (0,40) | .zip (51018) (0,46) | .zip (35322) (0,32) | .zip (35413) (0,32) | .zip (35415) (0,32) | .zip (35333) (0,32) |
lzh (44388) (0,40) | .lzh (56993) (0,51) | .lzh (66739) (0,60) | .lzh (44392) (0,40) | .lzh (44560) (0,40) | .lzh (44561) (0,40) | .lzh (44398) (0,40) |
book1.dat (768771) | .hex (1537542) (2,00) | .b64 (1025028) (1,33) | .v7 (768771) (1,00) | .s64 (769671) (1,00) | .s64r (769545) (1,00) | .rle (768647) (1,00) |
zip (313632) (0,41) | .zip (384788) (0,50) | .zip (415855) (0,54) | .zip (313691) (0,41) | .zip (313550) (0,41) | .zip (313568) (0,41) | .zip (313697) (0,41) |
lzh (353935) (0,46) | .lzh (442692) (0,58) | .lzh (497286) (0,65) | .lzh (353945) (0,46) | .lzh (354062) (0,46) | .lzh (354074) (0,46) | .lzh (353980) (0,46) |
book2.dat (610856) | .hex (1221712) (2,00) | .b64 (814476) (1,33) | .v7 (610856) (1,00) | .s64 (616479) (1,01) | .s64r (616184) (1,01) | .rle (610563) (1,00) |
zip (206947) (0,34) | .zip (255981) (0,42) | .zip (294077) (0,48) | .zip (206982) (0,34) | .zip (207502) (0,34) | .zip (207551) (0,34) | .zip (207065) (0,34) |
lzh (242018) (0,40) | .lzh (306274) (0,50) | .lzh (365304) (0,60) | .lzh (242027) (0,40) | .lzh (242789) (0,40) | .lzh (242858) (0,40) | .lzh (242132) (0,40) |
geo.dat (102400) | .hex (204800) (2,00) | .b64 (136536) (1,33) | .v7 (133377) (1,30) | .s64 (125331) (1,22) | .s64r (123675) (1,21) | .rle (100764) (0,98) |
zip (68744) (0,67) | .zip (73849) (0,72) | .zip (76980) (0,75) | .zip (70767) (0,69) | .zip (69310) (0,68) | .zip (69215) (0,68) | .zip (68678) (0,67) |
lzh (69400) (0,68) | .lzh (76861) (0,75) | .lzh (78878) (0,77) | .lzh (72452) (0,71) | .lzh (71183) (0,70) | .lzh (71123) (0,69) | .lzh (69336) (0,68) |
news.dat (377109) | .hex (754218) (2,00) | .b64 (502812) (1,33) | .v7 (377109) (1,00) | .s64 (387984) (1,03) | .s64r (376041) (1,00) | .rle (366663) (0,97) |
zip (145106) (0,38) | .zip (174271) (0,46) | .zip (207720) (0,55) | .zip (145144) (0,38) | .zip (146146) (0,39) | .zip (145631) (0,39) | .zip (145218) (0,39) |
lzh (161110) (0,43) | .lzh (202497) (0,54) | .lzh (250664) (0,66) | .lzh (161114) (0,43) | .lzh (162552) (0,43) | .lzh (161939) (0,43) | .lzh (160961) (0,43) |
obj1.dat (21504) | .hex (43008) (2,00) | .b64 (28672) (1,33) | .v7 (28051) (1,30) | .s64 (26195) (1,22) | .s64r (23186) (1,08) | .rle (18432) (0,86) |
zip (10575) (0,49) | .zip (11926) (0,55) | .zip (13217) (0,61) | .zip (11015) (0,51) | .zip (11032) (0,51) | .zip (11018) (0,51) | .zip (10589) (0,49) |
lzh (10583) (0,49) | .lzh (12144) (0,56) | .lzh (13365) (0,62) | .lzh (11099) (0,52) | .lzh (11094) (0,52) | .lzh (11013) (0,51) | .lzh (10510) (0,49) |
obj2.dat (246814) | .hex (493628) (2,00) | .b64 (329088) (1,33) | .v7 (317675) (1,29) | .s64 (297928) (1,21) | .s64r (294311) (1,19) | .rle (243214) (0,99) |
zip (81883) (0,33) | .zip (92030) (0,37) | .zip (115770) (0,47) | .zip (84723) (0,34) | .zip (84220) (0,34) | .zip (84175) (0,34) | .zip (81826) (0,33) |
lzh (88786) (0,36) | .lzh (105877) (0,43) | .lzh (128919) (0,52) | .lzh (93635) (0,38) | .lzh (92322) (0,37) | .lzh (92218) (0,37) | .lzh (88680) (0,36) |
paper1.dat (53161) | .hex (106322) (2,00) | .b64 (70884) (1,33) | .v7 (53161) (1,00) | .s64 (53822) (1,01) | .s64r (53653) (1,01) | .rle (52994) (1,00) |
zip (18832) (0,35) | .zip (22425) (0,42) | .zip (27081) (0,51) | .zip (18853) (0,35) | .zip (18910) (0,36) | .zip (18923) (0,36) | .zip (18877) (0,36) |
lzh (20931) (0,39) | .lzh (26633) (0,50) | .lzh (32017) (0,60) | .lzh (20938) (0,39) | .lzh (21050) (0,40) | .lzh (21058) (0,40) | .lzh (20964) (0,39) |
paper2.dat (82199) | .hex (164398) (2,00) | .b64 (109600) (1,33) | .v7 (82199) (1,00) | .s64 (82572) (1,00) | .s64r (82563) (1,00) | .rle (82192) (1,00) |
zip (30006) (0,37) | .zip (36784) (0,45) | .zip (41431) (0,50) | .zip (30031) (0,37) | .zip (30074) (0,37) | .zip (30080) (0,37) | .zip (30035) (0,37) |
lzh (33803) (0,41) | .lzh (42500) (0,52) | .lzh (49390) (0,60) | .lzh (33811) (0,41) | .lzh (33885) (0,41) | .lzh (33887) (0,41) | .lzh (33818) (0,41) |
paper3.dat (46526) | .hex (93052) (2,00) | .b64 (62036) (1,33) | .v7 (46526) (1,00) | .s64 (46805) (1,01) | .s64r (46805) (1,01) | .rle (46527) (1,00) |
zip (18351) (0,39) | .zip (22044) (0,47) | .zip (25415) (0,55) | .zip (18373) (0,39) | .zip (18423) (0,40) | .zip (18425) (0,40) | .zip (18376) (0,39) |
lzh (19958) (0,43) | .lzh (25129) (0,54) | .lzh (29191) (0,63) | .lzh (19965) (0,43) | .lzh (20040) (0,43) | .lzh (20041) (0,43) | .lzh (19970) (0,43) |
paper4.dat (13286) | .hex (26572) (2,00) | .b64 (17716) (1,33) | .v7 (13286) (1,00) | .s64 (13387) (1,01) | .s64r (13387) (1,01) | .rle (13287) (1,00) |
zip (5791) (0,44) | .zip (6843) (0,52) | .zip (8263) (0,62) | .zip (5812) (0,44) | .zip (5840) (0,44) | .zip (5842) (0,44) | .zip (5815) (0,44) |
lzh (5810) (0,44) | .lzh (7225) (0,54) | .lzh (8583) (0,65) | .lzh (5817) (0,44) | .lzh (5862) (0,44) | .lzh (5863) (0,44) | .lzh (5823) (0,44) |
paper5.dat (11954) | .hex (23908) (2,00) | .b64 (15940) (1,33) | .v7 (11954) (1,00) | .s64 (12150) (1,02) | .s64r (12146) (1,02) | .rle (11952) (1,00) |
zip (5250) (0,44) | .zip (6181) (0,52) | .zip (7555) (0,63) | .zip (5272) (0,44) | .zip (5302) (0,44) | .zip (5307) (0,44) | .zip (5279) (0,44) |
lzh (5219) (0,44) | .lzh (6397) (0,54) | .lzh (7721) (0,65) | .lzh (5228) (0,44) | .lzh (5283) (0,44) | .lzh (5284) (0,44) | .lzh (5234) (0,44) |
paper6.dat (38105) | .hex (76210) (2,00) | .b64 (50808) (1,33) | .v7 (38105) (1,00) | .s64 (38651) (1,01) | .s64r (38617) (1,01) | .rle (38073) (1,00) |
zip (13488) (0,35) | .zip (16145) (0,42) | .zip (19954) (0,52) | .zip (13512) (0,35) | .zip (13558) (0,36) | .zip (13569) (0,36) | .zip (13528) (0,36) |
lzh (15035) (0,39) | .lzh (18831) (0,49) | .lzh (22934) (0,60) | .lzh (15045) (0,39) | .lzh (15134) (0,40) | .lzh (15142) (0,40) | .lzh (15064) (0,40) |
pic.dat (513216) | .hex (1026432) (2,00) | .b64 (684288) (1,33) | .v7 (551367) (1,07) | .s64 (513916) (1,00) | .s64r (110705) (0,22) | .rle (104058) (0,20) |
zip (56693) (0,11) | .zip (63802) (0,12) | .zip (59543) (0,12) | .zip (60109) (0,12) | .zip (55972) (0,11) | .zip (50436) (0,10)2 | .zip (50636) (0,10) |
lzh (65232) (0,13) | .lzh (80688) (0,16) | .lzh (69954) (0,14) | .lzh (69117) (0,13) | .lzh (64820) (0,13) | .lzh (50468) (0,10) | .lzh (50359) (0,10) |
progc.dat (39611) | .hex (79222) (2,00) | .b64 (52816) (1,33) | .v7 (39611) (1,00) | .s64 (40824) (1,03) | .s64r (40102) (1,01) | .rle (38894) (0,98) |
zip (13530) (0,34) | .zip (16029) (0,40) | .zip (20202) (0,51) | .zip (13551) (0,34) | .zip (13672) (0,35) | .zip (13670) (0,35) | .zip (13659) (0,34) |
lzh (14967) (0,38) | .lzh (18816) (0,48) | .lzh (23408) (0,59) | .lzh (14979) (0,38) | .lzh (15191) (0,38) | .lzh (15149) (0,38) | .lzh (14962) (0,38) |
progl.dat (71646) | .hex (143292) (2,00) | .b64 (95528) (1,33) | .v7 (71646) (1,00) | .s64 (72039) (1,01) | .s64r (67085) (0,94) | .rle (66614) (0,93) |
zip (16527) (0,23) | .zip (19901) (0,28) | .zip (26211) (0,37) | .zip (16542) (0,23) | .zip (16572) (0,23) | .zip (16599) (0,23) | .zip (16631) (0,23) |
lzh (18274) (0,26) | .lzh (24552) (0,34) | .lzh (32122) (0,45) | .lzh (18263) (0,25) | .lzh (18332) (0,26) | .lzh (18199) (0,25) | .lzh (18235) (0,25) |
progp.dat (49379) | .hex (98758) (2,00) | .b64 (65840) (1,33) | .v7 (49379) (1,00) | .s64 (49767) (1,01) | .s64r (45607) (0,92) | .rle (45227) (0,92) |
zip (11500) (0,23) | .zip (13610) (0,28) | .zip (18923) (0,38) | .zip (11522) (0,23) | .zip (11540) (0,23) | .zip (11464) (0,23) | .zip (11504) (0,23) |
lzh (12612) (0,26) | .lzh (17333) (0,35) | .lzh (23299) (0,47) | .lzh (12622) (0,26) | .lzh (12701) (0,26) | .lzh (12502) (0,25) | .lzh (12493) (0,25) |
trans.dat (93695) | .hex (187390) (2,00) | .b64 (124928) (1,33) | .v7 (93695) (1,00) | .s64 (95767) (1,02) | .s64r (91810) (0,98) | .rle (89741) (0,96) |
zip (19238) (0,21) | .zip (24590) (0,26) | .zip (34867) (0,37) | .zip (19262) (0,21) | .zip (19639) (0,21) | .zip (19392) (0,21) | .zip (19350) (0,21) |
lzh (27274) (0,29) | .lzh (38061) (0,41) | .lzh (48232) (0,51) | .lzh (27286) (0,29) | .lzh (27580) (0,29) | .lzh (27551) (0,29) | .lzh (27286) (0,29) |
zip.dat (313632) | .hex (627264) (2,00) | .b64 (418176) (1,33) | .v7 (470189) (1,50) | .s64 (418176) (1,33) | .s64r (418176) (1,33) | .rle (313633) (1,00) |
zip (313955) (1,00) | .zip (357860) (1,14) | .zip (316738) (1,01) | .zip (353873) (1,13) | .zip (316738) (1,01) | .zip (316740) (1,01)3 | .zip (313972) (1,00) |
lzh (313976) (1,00) | .lzh (356321) (1,14) | .lzh (316733) (1,01) | .lzh (353426) (1,13) | .lzh (316733) (1,01) | .lzh (316734) (1,01) | .lzh (313985) (1,00) |
total: (3565125) (1,00) | (7130250) (2,00) | (4753520) (1,33) | (3868218) (1,09) | (3773340) (1,06) | (3335474) (0,94)4 | (3122737) (0,88) |
zip: (1385364) (0,39) | (1643015) (0,46) | (1780820) (0,50)1 | (1434356) (0,40) | (1393413) (0,39) | (1387020) (0,39)4 | (1380068) (0,39) |
lzh: (1523311) (0,43) | (1865824) (0,52) | (2064739) (0,58) | (1575161) (0,44) | (1535173) (0,43) | (1519664) (0,43) | (1508190) (0,42) |
Видно, что предложенный кодер S64, в среднем, показал хорошие результаты, превзойдя другие кодеры в текст, как по объему кода, так и по эффективности последующего сжатия LZ алгоритмами. Однако, результаты для конкретных файлов могут быть несколько хуже, чем при использовании кодера V7, в силу в двое более крупного алфавита последнего. Так же можно указать на следующее:
В данном эксперименте мы проверим, как влияет минимальная длина цепочки повтора LZ алгоритма на эффективность сжатия Hex кода. Предположение состоит в том, что минимальная длина цепочки повтора должна быть увеличена в два раза для эффективного сжатия таких данных. Для проверки мы модифицируем LZH компрессор и пересчитаем результаты. Ниже приведены для сравнения результаты обработки файла zip.dat (отдельно) и общие результаты сжатия всего набора. В каждом случае представлены 2 строки данных о сжатии: первая - с обычными настройками (как в предыдущем эксперименте), вторая (желтая) - с удвоенной минимальной длиной цепочки повтора.
zip.dat (313632) | .Hex (627264) (2,00) |
lzh (313976) (1,00) | .lzh (356321) (1,14) |
lzh (313964) (1,00) | .lzh (318478) (1,02) |
total: (3565125) (1,00) | (7130250) (2,00) |
lzh: (1523311) (0,43) | (1865824) (0,52) |
lzh: (1550016) (0,43) | (1815753) (0,51) |
Как видим, наше предположение подтвердилось - при увеличении минимальной длины цепочки LZ алгоритма степень сжатия Hex кода повысилась - особенно хорошо это видно в случае, если исходные данные имеют высокую энтропию. При этом средняя степень сжатия исходных данных, разумеется, ухудшилась.
В данном эксперименте мы убедимся, что на низкоэнтропийных данных с длинными цепочками повторяющихся значений эффективность поиска в LZ алгоритме может упасть. Для этого мы произведем сжатие наших данных алгоритмом LZH с максимально увеличенными глубиной поиска и длиной цепочки для ленивого сравнения. Приведем результаты для paper6.dat и pic.dat. Для каждого файла представлены 2 строки данных о сжатии: первая - с обычными настройками, вторая (желтая) - с экстремальными.
paper6.dat (38105) | .hex (76210) (2,00) | .b64 (50808) (1,33) | .v7 (38105) (1,00) | .s64 (38651) (1,01) | .s64r (38617) (1,01) | .rle (38073) (1,00) |
lzh (15035) (0,39) | .lzh (18831) (0,49) | .lzh (22934) (0,60) | .lzh (15045) (0,39) | .lzh (15134) (0,40) | .lzh (15142) (0,40) | .lzh (15064) (0,40) |
lzh (14990) (0,39) | .lzh (18548) (0,49) | .lzh (22876) (0,60) | .lzh (15000) (0,39) | .lzh (15089) (0,40) | .lzh (15099) (0,40) | .lzh (15017) (0,39) |
pic.dat (513216) | .hex (1026432) (2,00) | .b64 (684288) (1,33) | .v7 (551367) (1,07) | .s64 (513916) (1,00) | .s64r (110705) (0,22) | .rle (104058) (0,20) |
lzh (65232) (0,13) | .lzh (80688) (0,16) | .lzh (69954) (0,14) | .lzh (69117) (0,13) | .lzh (64820) (0,13) | .lzh (50468) (0,10) | .lzh (50359) (0,10) |
lzh (58612) (0,11) | .lzh (73071) (0,14) | .lzh (63937) (0,12) | .lzh (63130) (0,12) | .lzh (58902) (0,11) | .lzh (50207) (0,10) | .lzh (50163) (0,10) |
Легко видеть, что для файла paper6.dat изменение не привело к существенному улучшению сжатия, причем максимальный относительный результат в 1.5% получен для Hex кода (для него важна глубина поиска). В то же время, относительная разница в сжатии pic.dat (низкая энтропия, много повторов) превысила 10%, что подтверждает потерю эффективности поиска в LZ словаре. Также видно, что сжатие RLE кода pic.dat слабо зависит от параметров поиска LZ алгоритма, а степень сжатия лучше степени сжатия оригинальных данных.
Примечание. Применяемый LZH алгоритм имеет ограничения на глубину поиска в словаре и может использовать подход с ленивым сравнением (lazy matching).Исходный код. Реализация в функциях S64Encode, S64Decode. Все функции оперируют данными, хранимыми в длинной строке и возвращают строку (т. е. в памяти).