Бит чётности и контрольная сумма

Урок о том, как один лишний бит и простое сложение помогают заметить, что данные исказились по дороге.

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

Зачем это нужно

Любой канал связи и любой носитель ненадёжны. Радиоволна ловит помеху, на диске стирается участок, по кабелю проходит наводка — и бит, который был нулём, приходит единицей. Если передавать данные «как есть», получатель никак не узнает, что сообщение испортилось: набор битов остаётся внешне правильным. Чтобы заметить искажение, к данным заранее добавляют избыточные биты, вычисленные по строгому правилу. Получатель пересчитывает это правило сам и сравнивает с тем, что пришло.

Идея простая: пусть честный набор данных подчиняется некоторому условию. Тогда после ошибки условие нарушится, и приёмник это увидит. Чем «строже» условие, тем больше ошибок оно ловит — но и тем больше лишних битов нужно передавать. Это всегда компромисс между надёжностью и накладными расходами.

Бит чётности

Самый дешёвый способ обнаружения — добавить к группе битов ровно один контрольный, бит чётности (parity bit). Его выбирают так, чтобы общее число единиц во всей группе (вместе с контрольным битом) было чётным. Это называют чётной чётностью (even parity).

Пусть передаём байт 1011001 (семь информационных бит). Считаем единицы: их 4 — уже чётно. Значит, бит чётности равен 0, и в канал уходит 1011001 0. А для 1100001 единиц три — нечётно, поэтому бит чётности равен 1, чтобы довести их число до четырёх: уходит 1100001 1.

Формально бит чётности — это сумма всех информационных бит по модулю 2, то есть результат операции «исключающее ИЛИ» (XOR) над ними:

$$ p = b_1 \oplus b_2 \oplus \dots \oplus b_n $$

где $\oplus$ — сложение по модулю 2 ($0\oplus 0=0$, $1\oplus 0=1$, $1\oplus 1=0$). На приёмной стороне считают XOR уже всех бит вместе с контрольным. Если ошибок не было, результат равен нулю:

$$ b_1 \oplus \dots \oplus b_n \oplus p = 0 $$

Если же ровно один бит «перевернулся», сумма единиц изменит чётность, и XOR даст 1 — сигнал тревоги.

Что бит чётности умеет и чего не умеет

Бит чётности обнаруживает любое нечётное число ошибок (одну, три, пять...). Но он не видит чётное число ошибок: если перевернулись сразу два бита, число единиц снова станет чётным, и проверка пройдёт как ни в чём не бывало. И даже обнаружив ошибку, бит чётности не знает, какой именно бит испортился, — исправить он ничего не может. Это инструмент только обнаружения.

Контрольная сумма пакета

Когда данных много, их режут на байты и передают пакетом. Защищать каждый байт отдельным битом чётности дорого и слабо. Поэтому считают одну контрольную сумму (checksum) на весь пакет: складывают все байты и передают результат вместе с данными. Приёмник складывает принятые байты заново и сверяет сумму.

В простейшем варианте берут сумму байтов по модулю 256 (то есть младший байт обычной суммы):

$$ S = \left( \sum_{i=1}^{n} B_i \right) \bmod 256 $$

Разберём на числах. Пусть пакет — это байты 200, 100, 50. Их сумма равна 350, а $350 \bmod 256 = 94$. Значит, контрольная сумма пакета равна 94, её и приписывают в конец. Если при передаче 100 превратится в 101, приёмник получит сумму 351, $351 \bmod 256 = 95 \neq 94$ — ошибка поймана.

Как это работает

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

Посчитаем оба отпечатка на рабочем Python: бит чётности байта и контрольную сумму пакета. XOR здесь — оператор ^, а взятие по модулю — %.

def parity_bit(bits):
    p = 0
    for b in bits:
        p ^= b          # накапливаем XOR всех бит
    return p

data = [1, 0, 1, 1, 0, 0, 1]   # семь информационных бит
p = parity_bit(data)
frame = data + [p]
print("Данные:", data)
print("Бит чётности:", p)
print("Кадр в канал:", frame)
print("Единиц в кадре:", sum(frame), "(должно быть чётным)")

# Контрольная сумма пакета по модулю 256
packet = [200, 100, 50]
checksum = sum(packet) % 256
print("\nПакет:", packet)
print("Сумма:", sum(packet))
print("Контрольная сумма:", checksum)

# Имитируем ошибку: 100 пришло как 101
bad = [200, 101, 50]
print("Сумма с ошибкой:", sum(bad) % 256, "-- не совпала, ошибка поймана")

Вывод:

Данные: [1, 0, 1, 1, 0, 0, 1]
Бит чётности: 0
Кадр в канал: [1, 0, 1, 1, 0, 0, 1, 0]
Единиц в кадре: 4 (должно быть чётным)

Пакет: [200, 100, 50]
Сумма: 350
Контрольная сумма: 94
Сумма с ошибкой: 95 -- не совпала, ошибка поймана

Частые ошибки

  • Думать, что бит чётности ловит любые ошибки. Он ловит только нечётное их число; две перевернувшиеся единицы он пропускает.
  • Путать обнаружение и исправление. Бит чётности и контрольная сумма только сообщают, что данные испорчены, но не говорят, где именно, — восстановить исходное они не могут.
  • Забывать про модуль в контрольной сумме. Сумма байтов легко вырастает больше 255, поэтому её берут по модулю (обычно 256), иначе она не помещается в один байт.
  • Считать единицы только в данных, забыв контрольный бит. Чётность проверяют по всему кадру целиком, включая сам бит чётности.

Итоги

  • Избыточность — это дополнительные биты по строгому правилу, позволяющие заметить искажение данных.
  • Бит чётности — один бит, доводящий число единиц до чётного; равен XOR всех информационных бит.
  • Он обнаруживает нечётное число ошибок, но не чётное и ничего не исправляет.
  • Контрольная сумма — отпечаток целого пакета (например, сумма байтов по модулю 256); приёмник пересчитывает её и сверяет.
  • Все эти методы только обнаруживают ошибку; чтобы её исправить, нужна более хитрая схема — код Хэмминга из следующего урока.
Проверьте себя
1. К семибитному данному 1100001 добавляют бит чётности по схеме even parity (общее число единиц должно стать чётным). Чему равен бит чётности?
A0
B1
Cзависит от порядка бит
Dего нельзя определить без контрольной суммы
2. Какую ошибку бит чётности гарантированно НЕ обнаружит?
Aодиночную ошибку (перевернулся один бит)
Bперевернулись сразу два бита
Cошибку в самом бите чётности
Dтройную ошибку (три бита)