
- •Метод арифметичного кодування
- •Постановка задачи Тема работы: Сжатие текстовой информации методом арифметического кодирования. Задание:
- •Реализация метода
- •Разработанный проект
- •Проект, разработанный на wpf
- •Решение задачи ргр
- •Исходный код программы
- •Класс, представляющий алфавит
- •Класс, реализующий алгоритм арифметического кодирования
- •Класс главного окна
- •Итак, если Вам важно качественно сжать данные, то используйте арифметическое кодирование. Если же Вам нужно быстро реализовать процесс компрессии, то лучше выбрать алгоритм Хаффмана.
Класс главного окна
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public List<Letter> Letters { get; set; }
private Arithmetic arithmetic; // algo core
public String Power
{
get { return arithmetic == null ? "null" : "2^" + arithmetic.Power + "=" + BigInteger.Pow(new BigInteger(2), arithmetic.Power); }
}
public String LeftEdgeBinary
{
get
{
if (arithmetic == null) return "null";
var res = "";
var tmp = arithmetic.Left;
for (var i = 0; i < arithmetic.Power; i++)
{
var rem = new BigInteger();
tmp = BigInteger.DivRem(tmp, new BigInteger(2), out rem);
res += rem.IsOne ? "1" : "0";
}
char[] arr = res.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
}
public String RightEdgeBinary
{
get
{
if (arithmetic == null) return "null";
var res = "";
var tmp = arithmetic.Right;
for (var i = 0; i < arithmetic.Power; i++)
{
var rem = new BigInteger();
tmp = BigInteger.DivRem(tmp, new BigInteger(2), out rem);
res += rem.IsOne ? "1" : "0";
}
char[] arr = res.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
}
public String LeftEdge
{
get { return arithmetic == null ? "null" : arithmetic.Left.ToString(); }
}
public String RightEdge
{
get { return arithmetic == null ? "null" : arithmetic.Right.ToString(); }
}
public String EncodedText
{
get { return arithmetic == null ? "null" : arithmetic.EncodedText; }
}
public MainWindow()
{
// Edit alphabet here
Letters = new List<Letter>
{
///////////////// EXAMPLE ////////////////////////////////
//new Letter {Char = 'a', Name = "a", Probability = 0.750},
//new Letter {Char = 'b', Name = "b", Probability = 0.250},
///////////////////////////////////////////////////////////
/////////////////////// REAL LIFE /////////////////////////
new Letter {Char = 'о', Name = "о", Probability = 0.095},
new Letter {Char = 'е', Name = "е", Probability = 0.074},
new Letter {Char = 'а', Name = "а", Probability = 0.064},
new Letter {Char = 'и', Name = "и", Probability = 0.064},
new Letter {Char = 'т', Name = "т", Probability = 0.056},
new Letter {Char = 'н', Name = "н", Probability = 0.056},
new Letter {Char = 'с', Name = "с", Probability = 0.047},
new Letter {Char = 'р', Name = "р", Probability = 0.041},
new Letter {Char = 'в', Name = "в", Probability = 0.039},
new Letter {Char = 'л', Name = "л", Probability = 0.036},
new Letter {Char = 'к', Name = "к", Probability = 0.029},
new Letter {Char = 'м', Name = "м", Probability = 0.026},
new Letter {Char = 'д', Name = "д", Probability = 0.026},
new Letter {Char = 'п', Name = "п", Probability = 0.024},
new Letter {Char = 'у', Name = "у", Probability = 0.021},
new Letter {Char = 'я', Name = "я", Probability = 0.019},
new Letter {Char = 'ы', Name = "ы", Probability = 0.016},
new Letter {Char = 'з', Name = "з", Probability = 0.015},
new Letter {Char = 'ь', Name = "ь", Probability = 0.01},
new Letter {Char = 'ъ', Name = "ъ", Probability = 0.013},
new Letter {Char = 'б', Name = "б", Probability = 0.013},
new Letter {Char = 'г', Name = "г", Probability = 0.01},
new Letter {Char = 'ч', Name = "ч", Probability = 0.01},
new Letter {Char = 'й', Name = "й", Probability = 0.01},
new Letter {Char = 'х', Name = "х", Probability = 0.009},
new Letter {Char = 'ж', Name = "ж", Probability = 0.007},
new Letter {Char = 'ю', Name = "ю", Probability = 0.007},
new Letter {Char = 'ш', Name = "ш", Probability = 0.006},
new Letter {Char = 'ц', Name = "ц", Probability = 0.002},
new Letter {Char = 'щ', Name = "щ", Probability = 0.002},
new Letter {Char = 'э', Name = "э", Probability = 0.002},
new Letter {Char = 'ф', Name = "ф", Probability = 0.002},
new Letter {Char = ',', Name = ",", Probability = 0.002},
new Letter {Char = '.', Name = ".", Probability = 0.002},
new Letter {Char = ' ', Name = "пробел", Probability = 0.145},
};
InitializeComponent();
this.DataContext = this;
}
private void update()
{
// Update all values
NotifyPropertyChanged("LeftEdge");
NotifyPropertyChanged("RightEdge");
NotifyPropertyChanged("LeftEdgeBinary");
NotifyPropertyChanged("RightEdgeBinary");
NotifyPropertyChanged("EncodedText");
NotifyPropertyChanged("Power");
}
private void ButtonNext_OnClick(object sender, RoutedEventArgs e)
{
if (arithmetic == null) return;
arithmetic.MakeAStep(); // make a step
update();
}
private void ButtonStartRestart_OnClick(object sender, RoutedEventArgs e)
{
if (String.IsNullOrEmpty(TextBoxInput.Text)) return;
// start an algo
arithmetic = new Arithmetic(Letters, TextBoxInput.Text.Length, TextBoxInput.Text);
update();
}
private void ButtonFinal_OnClick(object sender, RoutedEventArgs e)
{
if (arithmetic == null) return;
while (!arithmetic.MakeAStep()); // make all steps
update();
}
// For auto updating
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Выводы
В результате выполнения лабораторной работы была разработана программа для работы по алгоритму арифметического кодирования.
Данный алгоритм опережает алгоритм Хаффмана по показателям сжатия. Но существует ряд практических проблем при реализации. Мы знаем, что Хаффман довольно просто кодируется и представляется в памяти ЭВМ. В этом и состоит его главное преимущество. При арифметическом кодировании стоит проблема точности вычислений. В реальном алфавите довольно маленькие вероятности появления символов. Закодировав небольшое предложение, мы уже получаем угрозу вылететь за пределы точности выбранного нами типа данных. Здесь есть 3 варианта решения проблемы:
Использование блочного кодирования. Каждый блок будет иметь такую длину, которую максимально может позволить точность стандартного типа данных с плавающей точкой. Нужно заметить, что эта длина будет одинаковой для всех передаваемых блоков.
Использование "длинной арифметики". Математические операции позволяют перевести расчеты в множество целых чисел, и далее оперировать на уровне классов типа BigInteger, которые вмещают произвольное целое число.
Сохранение неизменяющихся цифр. Во время выполнения алгоритма некоторые цифры стают одинаковыми для обоих границ диапазона. Их можно сохранять в другое место, чтобы освободить память для новых цифр.