ZX Review
#5-6
04 ноября 1997 |
|
Форум - Компрессия программ.
Компрессия программ Для начала наболевшая тема: компрессия текста. Практически идеальным вариантом является компрессия текста по методу Хаф- фмана (в чистом виде) - для тек- стов (больших размеров) данный метод более прогрессивен, чем LZSS (про RLE вообще молчу). Про компрессию Хаффмана и пойдет речь. Теория Тексты обыкновенно пишут ли- бо на русском, либо на англий- ском языках, поэтому часто пов- торяться будут не более 90 (ла- тинский) или 120-140 букв (рус- ский). Причем по приблизительным расчетам 30% из них занимают очень часто встречающиеся буквы. Из всего этого следует, что нам нужно преобразовать алгоритм компрессии Хаффмана так, чтобы он работал в этих условиях. Первое, что нам нужно сде- лать - составить таблицу по час- тоте используемых элементов - массив из 256 байт. На первом месте должен стоять наиболее ча- сто встречающийся символ, на по- следнем - наименее. Примеров приводить не буду, т.к. сделать это очень легко. Итак, массив получен, теперь самое главное: разрабатываем формат, в котором будут хранить- ся данные. Принцип такой: все числа делятся на 5 групп по чис- лу битов: Группа Кол-во битов 1 1 2 2 3 3 4 4-8 Числа с 1-ой по 3-ю группу кодируются так: сначала идет N включенных битов - какой номер группы, столько битов. Затем идет само число (битов по груп- пе), причем первое его значение установлено в 0. (Для более лег- кого усвоения материала см. ZX- Ревю 1/95). Пример: Число 0. Занимает 1 бит: %0. Число 1-ой группы. Значит, оно будет выглядеть как %10 - всего 2 бита. Число 3. Занимает 2 бита: %11. 2-я группа: %11 01 - четыре бита. Само число преобразовано из %11 в %01, чтобы програм- ма-декомпрессор могла подсчитать номер группы. Как видите, чем больше груп- па, тем меньше выигрыш: Группа Выигрыш (бит) 1 6 2 4 3 2 Но все равно выигрыш очень велик. Но если пойти дальше по этому пути, то 8-битные числа будут кодировать 16 битами, 7-битные - 14, что нас не устра- ивает. Поэтому для 4-8 групп приме- нен специальный формат: вместо единиц с номером группы записы- вается бит = 0 - признак спец- формата. Затем мы записываем еще один бит: если он равен 0, то за ним идет нормальное восьмибитное число (в случае 6, 7, 8 групп). Если он равен 1, то за ним идет 5-битовое число (4, 5 группа). Группа (бит) Выигрыш (бит) 4 +1 5 +1 6 -2 7 -2 8 -2 Пример: число 255. 8-я груп- па, %11111111. После компрессии: %00 %11111111 (потеря 2-х байт). Число 64. 7-я группа, %01000 000. Результат: %00 %01000000 (опять потеря). Число 8. 4-я группа, %0000100 0. Результат: %01 %01000 (выиг- рыш 1 бита). Но ведь чисел с номерами 32 - 255 подавляющее большин- ство - скажете вы. Вот тут и дает себя знать алгоритм Хаффма- на: ведь в таблице мы закодиро- вали наиболее встречающиеся сим- волы меньшими кодами, а, особен- но в текстах, такие символы и составят у нас большинство (в русском и английском - гласные, пробелы). Алгоритм: декомпрессирующая программа должна расскомпресси- ровать код, затем по таблице найти соответствующий ему сим- вол. Пример такого декомпрессора: (программа сырая, не релоцируе- мая, не оптимизирована). Данная программа только осу- ществляет конвертирование в коды из компрессированного файла. Вам нужно писать свою процедуру по- лучения исходного кода по табли- це (вычисляется из полученного кода операциями: LD L,N ;N-номер кода LD H,0 ;в двухбайтную форму LD DE,TABLE ;адрес таблицы ADD HL,DE ;вычисляем адрес LD A,(HL) ;получили код Вход в программу: IY - адрес компрессированного блока, IX - адрес, куда происходит деком- прессия. Формат компрессирован- ного файла: сначала идут 2 бай- та - длина файла перед компрес- сией (сколько всего кодов).140. ORG 32768 LD E,(IY+0) ;берем длину LD D,(IY+1) INC IY INC IY ;в IY-адрес файла LD (LONG),DE ;сохраняем длину LD D,7 ;бит 7. MAIN CALL GRUPPA ;берем номер группы CALL PRIEM ;вычисляем код PUSH BC LD BC,(LONG) DEC BC ;уменьшили длину LD (LONG),BC LD A,B OR C POP BC JR NZ,MAIN ;в цикл RET LONG DW 0 ;сохраняет длину ;увеличение битового адреса INCBIT PUSH AF ;сохранили A LD A,D ;номер бита AND A ;если =0, то JR Z,NEWBYTE ; переход DEC A ;уменьшили номер LD D,A ;в регистр D POP AF ;восстановили A RET ;Выход NEWBYTE LD D,7 ;новый байт.Бит 7 INC IY ;увеличили байтовый POP AF ; адрес.Восстановили RET ; A и выход ;проверка бита из адреса ;если бит=0, то в A будет 0, если бит=1, ;то в A будет 255. GETBIT LD A,#47 ;код BIT 0,A GETBIT1 PUSH BC ;запомнили BC LD (BT+1),A ;вставили код LD A,D AND A ;если бит 0 ,то JR Z,PROH ; переход LD B,A ;счетчик битов UST LD A,(BT+1) ;устанавливаем ADD A,8 ; команды BIT 0,A LD (BT+1),A ; 1,2,3,4,5,6,7 DJNZ UST PROH LD A,(IY+0) ;берем байт BT BIT 0,A ;проверяем бит POP BC ;восстанавливаем BC IZ DB 0 JR Z,BIT0 ;если бит=0,переход BIT1 LD A,255 ;бит=1 RET BIT0 XOR A ;бит=0 RET ;включение бита из адреса SETBIT PUSH AF ;запомнили A LD A,#C9 ;используем GETBIT LD (IZ),A ; из SETBIT:код RET LD A,#C7 ;код SET 0,A CALL GETBIT1 ;в A-полученный байт LD (IY+0),A ;байт в адрес XOR A ;восстановили LD (IZ),A ; GETBIT POP AF ;восстановили A RET ;получение номера группы ;вход: битовый адрес на указателе группы GRUPPA CALL GETBIT ;берем бит AND A ;равен 0 ? JR Z,GRUP58 ;5-8 битное число CALL INCBIT ;увеличили адрес LD C,1 ;счетчик группы GR1 CALL GETBIT ;взяли бит AND A ;равен 0 ? JR Z,GR2 ;если да,пошло число INC C ;увеличили группу CALL INCBIT ;увеличили адрес JR GR1 ;в цикл GR2 CALL SETBIT ;включили бит(т.к. 1 LD B,C ;бит числа, равный 1 RET ;установлен в 0 GRUP58 CALL INCBIT ;увеличили адрес CALL GETBIT ;взяли бит AND A ;равен 0 ? JR Z,GRUP5 ;5-битное число GRUP8 CALL INCBIT ;8-битное число LD B,8 ;группа 8 RET GRUP5 CALL INCBIT ;увеличили адрес LD B,5 ;группа 5 RET ;получение числа. B-номер группы ;битовый адрес на числе. PRIEM XOR A ;обнулили ротируемый LD (BYTE),A ;байт-приемник PR CALL GETBIT ;взяли бит AND A ;если не равен 0, то CALL NZ,WKL ;включаем бит в BYTE LD A,(BYTE) ;ротация байта- RLA ; приемника LD (BYTE),A CALL INCBIT ;увеличили адрес DJNZ PR ;номер группы=циклам LD (IX+0),A ;получили код INC IX ;увеличили адрес RET ; приемника WKL SCF ;включение бита RET BYTE DB 0 ;байт-приемник 2 Из этого вытекает несколько особенностей компрессии Хаффма- на: 1. На мелких файлах (по рас- четам, до 3 Кб) компрессор не даст выигрыша, так как сама де- компрессирующая программа будет довольно большая - нужно сохра- нить таблицу (уже 256 байт) и т.д. 2. Чем больше файл и чем меньше в нем используемых симво- лов, тем мощнее компрессия. 3. Главная особенность: в от- личие от других компрессоров (LZSS, RLE), в компрессированном файле хранятся не данные, а их коды!!! Поэтому изменять их ни в коем случае нельзя. (А вот в LZSS и, тем более, в RLE, можно: влез доктором в файл на диске, поискал свою надпись - может, она и не скомпрессировалась - и если нашел, то изменил как нуж- но. Здесь же вы не только ничего не найдете, но и еще испортите ВЕСЬ файл...) 4. Малая скорость декомпрес- сора (по сравнению с другими технологиями). Но это все теория - так что, кто попробует алгоритм Хаффмана на практике - напишите в Ревю. Прим. ред.: Можно значительно сократить таблицу частот символов, если учесть, что символы с номерами 32-255 кодируются оди- наковым числом битов (десятью битами), и, следовательно, порядок их расположения в таблице не влияет на размер сжатого файла. Таким образом, в таблице достаточно хра- нить лишь 32 наиболее часто используемых символа. И еще. Попробуйте реализовать улучшен- ный алгоритм Хаффмана, в котором кодируют- ся как отдельные символы, так и наиболее часто встречающиеся пары символов. Напри- мер, в тексте на английском языке часто встречается пара символов "th". Очевид- но, длина кода, соответствующего этой паре символов, будет меньше, чем сумма длин ко- дов символов "t" и "h". За счет этого дос- тигается превосходство в сжатии. * * * (c) Иван Рощин, г.Москва, 1997 Особенности ассемблера ZX ASM 3.0 При выполнении команды "Load sts" (в меню Setup) в случае, если файл с указанным именем не будет найден, сообщение об ошиб- ке не выдается. Если установлен режим Edit mode = Text, вы лишаетесь воз- можности доступа ко всем пунктам меню Run, кроме Inspect, что не всегда удобно. Не выдается сообщение об ошибке при ассемблировании ко- манды загрузки в однобайтный ре- гистр двухбайтного числа. Напри- мер, команда LD B,#1234 будет ассемблирована как LD B,#34. ZX ASM почему-то считает, что регистры HL, IX, IY равноправны, т.е. в любой команде, использую- щей HL, можно использовать и ре- гистры IX, IY. Если в командах типа LD A,(HL) это действительно так, то к командам типа ADD HL, HL и к некоторым другим это не относится. Поясню сказанное на примере: Исходный текст │ Компилируется ───────────────┼────────────── ADD HL,IX │ ADD HL,HL SBC HL,IY │ SBC HL,HL EX DE,IX │ EX DE,HL Эта ошибка может привести к крайне неприятной ситуации. На- пример, вы в своей программе на- писали ADD HL,IX, забыв, что та- кой команды нет. Ассемблер так- же "ничего не заметил", а потом вы удивляетесь, почему ваша про- грамма не работает. В командах, работающих с по- ловинками индексных регистров, должны использоваться обозначе- ния XL,XH,YL,YH. Между тем, STS в этих же командах использует обозначения LX,HX,LY,HY. Некорректно обрабатывается ситуация, когда вы определяете переменную с помощью DS, а коли- чество отводимых под нее байтов равно нулю. Такой случай может возникнуть, например, если вы сначала определили переменную с помощью DB, а потом решили заме- нить DB на DS, при этом забыв заменить 0 на 1: NAME DB 0 -> NAME DS 0 Если текст программы изменял- ся с момента последней записи на диск, ZX ASM перед выполнением "опасных" операций предложит со- хранить его. Но как же ZX ASM определяет, изменялся текст или нет? Очевидно, просто путем сра- внения контрольной суммы текста, находящегося в памяти, и текста, в последний раз записанного на диск. Но этот способ в некоторых случаях дает неправильный ре- зультат, и ZX ASM считает, что текст не изменился: а) LD HL,#1234 LD HL,#3214 DB %01100110 DB %11001100 (т.к. изменение порядка символов не влияет на контрольную сумму текста) б) LD A,5 LD A,4 LD B,6 LD B,7 (т.к. ASC-коды символов "5" и "6" в сумме равны #35+#36=#6B, и этой же величине равна сумма кодов символов "4" и "7"). * * *
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября