Имя: Пароль:
IT
 
Арифметическое кодирование.
0 megabax
 
27.10.16
10:04
Подскажите пожалуйста идею, как решить проблему потери точности при арифметическом кодировании. Допустим есть у меня вот такой код на C#
            low = 0;
            high = 1;
            int i = next_simbol();
            while (i != -1)
            {                
                double range = high - low;
                double dhigh = range * dictionary.items[i].p;
                if (i > 0)
                {
                    low = low + range * dictionary.items[i - 1].p;
                }
                high=low+dhigh;
                i = next_simbol();
            }
где low и high переменные типа double. Но уже при кодировании 21 буквы high и low отличаются только одной значащей цифрой, а дальше они вообще сливаются. Как можно решить эту проблему? Написать свои классы супервысокой точности? Или каким-то волшебным образом интервал сразу кодировать в бинарном коде?
1 megabax
 
27.10.16
10:35
up
2 Волшебник
 
модератор
27.10.16
10:38
перестать заниматься хернёй
3 Кирпич
 
27.10.16
10:38
нифига не понял где тут дебет и где кредит
4 megabax
 
27.10.16
10:41
(2) Это не херня, это лабораторная работа в институте.
5 Волшебник
 
модератор
27.10.16
10:42
(4) все лабораторные работы в институтах - херня
6 ovrfox
 
31.10.16
20:02
Алгоритм, который здесь указан ничего не кодирует. (В смысле не уменьшает размер). Соответственно данное суммирование быстро приводит к переполнению переменных.

Советую проверить алгоритм.
7 megabax
 
31.10.16
20:29
(6)Да, вы правы. Переделал вот так:
            low = 0;
            high = 1;
            StringBuilder sb = new StringBuilder();

            int i = next_simbol();
            while (i != -1)
            {
                double range = high - low;

                RangeDictionaryItem item = dictionary.items[i] as RangeDictionaryItem;

                high = low + range * item.end;
                low = low + range * item.beg;

                sb.AppendFormat("{0};[{1};{2});{3};{4};{5}\n", i, low, high, range, item.beg, item.end);

                i = next_simbol();
            }
И обратный алгоритм:
            high = 1;
            low = 0;
            for (int i = 1; i <= count; i++)
            {
                DictionaryItem item=dictionary.items.Find(
                    delegate(DictionaryItem litem)
                    {
                        return (litem as RangeDictionaryItem).beg <= (value - low) / (high - low)
                            && (value - low) / (high - low) < (litem as RangeDictionaryItem).end;
                    }
                );
                output_text += item.simbol;

                double range = high - low;
                high = low+range * (item as RangeDictionaryItem).end;
                low = low + range * (item as RangeDictionaryItem).beg;
            }

но проблема осталось. Успешно кодирует и декодирует только примерно 10 символов, а дальше уже не может отработать обратное декодирование.
Возникла идея double заменить на decimal, но он тоже не безграничный.
Вот непонятно, как тут быть? Кодировать блоками? Или вводить какие-то коэффициенты и когда разница становиться маленькой, умножать на них? Или может разработать свои суперточные числа?
8 NorthWind
 
31.10.16
21:19
(7) >> Или может разработать свои суперточные числа?
Зачем? Если вам не хватает того, что после запятой, вы можете использовать то, что до.