Контрольные суммы

Хранение данных и их передача часто сопровождается или может сопровож­даться ошибками. Приемнику и передатчику информации необходимо знать, что данные в потоке должны соответствовать определенным прави­лам. Приводя реальный поток в соответствие с этими правилами, приемник может восстановить его исходное содержание. Количество и типы практиче­ски восстановимых ошибок определяются применяемыми правилами коди­рования. Понятно, что всегда существует (и во многих случаях может быть теоретически оценен) порог количества ошибок в сообщении, после кото­рого сообщение не поддается даже частичному восстановлению.

Простейшим способом внесения избыточности является полное дублирова­ние данных. Благодаря своей простоте, этот способ иногда применяется на практике, но обладает многочисленными недостатками. Во-первых, избы­точность этого метода чрезмерно высока для многих практических приме­нений. Во-вторых, он позволяет только обнаруживать ошибки, но не ис­правлять их: при отсутствии других правил кодирования, мы не можем знать, какая из копий верна, а какая ошибочна.

Троекратное копирование обеспечивает еще более высокую избыточность, зато при его использовании для каждого расходящегося бита мы можем проводить голосование: считать правильным то значение, которое присутст­вует минимум в двух копиях данных (в данном случае мы исходим из того, что вероятность ошибки в одном и том же бите двух копий достаточно мала).

Трехкратное копирование, таким образом, позволяет восстанавливать дан­ные, но имеет слишком уж высокую избыточность. Эти примеры, кроме простоты, любопытны тем, что демонстрируют нам практически важную классификацию избыточных кодов: бывают коды, которые только обнару­живают ошибки, а бывают и такие, которые позволяют их восстанавливать. Далеко не всегда коды второго типа могут быть построены на основе кодов пер­вого типа. Во многих случаях, например при передаче данных по сети, целесо­образно запросить повтор испорченного пакета, поэтому коды, способные толь­ко обнаруживать ошибки, практически полезны и широко применяются.

Простейший из применяемых способов кодирования с обнаружением оши­бок — это бит четности. Блок данных снабжается дополнительным битом, значение которого выбирается так, чтобы общее количество битов, равных единице, в блоке было четным. Такой код позволяет обнаруживать ошибки в одном бите блока, но не в двух битах (строго говоря — позволяет обнару­живать нечетное количество ошибочных битов). Если вероятность ошибки в двух битах достаточно велика, нам следует либо разбить блок на два блока меньшего размера, каждый со своим битом четности, либо использовать бо­лее сложные схемы кодирования.

Самая распространенная из таких более сложных схем — это CRC (Cyclic Redundancy Code, циклический избыточный код). При вычислении CRC разрядности N выбирают число R требуемой разрядности и вычисляют оста­ток от деления на R блока данных (рассматриваемого как единое двоичное число), сдвинутого влево на N битов. Двоичное число, образованное блоком данных и остатком, делится на R, и этот факт можно использовать для про­верки целостности блока (но не для восстановления данных при ошибке!).

Способность контрольной суммы обнаруживать ошибки логичнее измерять не в количестве ошибочных битов, а в вероятности необнаружения ошибки. При использовании CRC будут проходить незамеченными лишь сочетания ошибок, удовлетворяющие весьма специальному условию, а именно такие, вектор ошибок (двоичное число, единичные биты которого соответствуют ошибочным битам принятого блока, а нулевые — правильно принятым) ко­торых делится на R. При случайном распределении ошибок вероятность этого может быть грубо оценена как 1/R, поэтому увеличение разрядности контрольной суммы в сочетании с выбором простых R обеспечивает доста­точно быстрый и дешевый способ проверки целостности даже довольно длинных блоков. 32- разрядный CRC обеспечивает практически полную га­рантию того, что данные не были повреждены, а 8-разрядный — уверен­ность, достаточную для многих целей. Однако ни четность, ни CRC не мо­гут нам ничем помочь при восстановлении поврежденных данных.

Простой метод кодирования, позволяющий не только обнаруживать, но и исправлять ошибки, называется блочной или параллельной четностью и со­стоит в том, что мы записываем блок данных в виде двухмерной матрицы и подсчитываем бит четности для каждой строки и каждого столбца. При одиночной ошибке, таким образом, мы легко можем найти бит, который портит нам жизнь. Двойные ошибки такая схема кодирования может обна­руживать, но не способна восстанавливать (рис. 1.9).

Данные

Биты
                                                      четности
 
 
 
   

Биты четности

Рис.1.9- Параллельная четность

Широко известный и применяемый код Хэмминга (Hamming code) находится в близком родстве с параллельной четностью. Его теоретическое обоснова­ние несколько менее очевидно, чем у предыдущего алгоритма, но в реализа­ции он, пожалуй, даже проще [Берлекэмп 1971]. Идея алгоритма состоит в том, чтобы снабдить блок данных несколькими битами четности, подсчи­танными по различным совокупностям битов данных. При выполнении не­равенства Хэмминга (1.1) сформированный таким образом код обеспечивает обнаружение и исправление одиночных ошибок либо гарантированное об­наружение (но не исправление!) двойных ошибок. Важно подчеркнуть га­рантию обнаружения, в отличие от всего лишь высокой вероятности обна­ружения при использовании CRC.

d + p+l<2P, (1.1)

где d — количество битов данных, р — разрядность контрольного кода.

Код, использующий d и р, при которых выражение (1.1) превращается в ра­венство, называют оптимальным кодом Хэмминга.

Часто оказывается целесообразно сочетать упаковку данных с их избыточ­ным кодированием. Наиболее удачным примером такой целесообразности опять-таки являются тексты на естественных языках: статистический анализ такого текста показывает очень высокий, более чем двукратный, уровень избыточности. С одной стороны, это слишком много для большинства практически применяемых способов цифровой передачи и кодирования данных, а с другой — правила формирования этой избыточности слишком сложны и плохо формализованы для использования в современных про­граммно-аппаратных комплексах. Поэтому для длительного хранения или передачи по низкоскоростным линиям целесообразно упаковывать тексто­вые данные и снабжать их простыми средствами избыточности, например CRC.