Исправьте ошибки, используя Хэмминга (7,4)

19

Код Хэмминга (7,4) восходит к 1950 году. В то время Ричард Хэмминг работал математиком в Bell Labs. Каждую пятницу Хэмминг настраивал вычислительные машины на выполнение серии расчетов и собирал результаты в следующий понедельник. Используя проверки на четность, эти машины смогли обнаружить ошибки во время вычислений. Разочарованный, потому что он получал сообщения об ошибках слишком часто, Хэмминг решил улучшить обнаружение ошибок и обнаружил известные коды Хемминга.

Механика Хэмминга (7,4)

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

В качестве примера кодов Хэмминга мы рассмотрим код Хемминга (7,4). В дополнение к 4 битам данных d1, d2, d3, d4используются 3 бита четности p1, p2, p3, которые рассчитываются с использованием следующих уравнений:

p1 = (d1 + d2 + d4) % 2
p2 = (d1 + d3 + d4) % 2
p3 = (d2 + d3 + d4) % 2

Результирующее кодовое слово (данные + биты четности) имеет вид p1 p2 d1 p3 d2 d3 d4.

Обнаружение ошибки работает следующим образом. Вы пересчитываете биты четности и проверяете, соответствуют ли они принятым битам четности. В следующей таблице вы можете видеть, что каждое разнообразие однобитовой ошибки приводит к различному соответствию битов четности. Следовательно, каждая однобитовая ошибка может быть локализована и исправлена.

error in bit | p1 | p2 | d1 | p3 | d2 | d3 | d4 | no error
-------------|---------------------------------------------
p1 matches   | no | yes| no | yes| no | yes| no | yes
p2 matches   | yes| no | no | yes| yes| no | no | yes
p3 matches   | yes| yes| yes| no | no | no | no | yes

пример

Пусть ваши данные будут 1011. Биты четности есть p1 = 1 + 0 + 1 = 0, p2 = 1 + 1 + 1 = 1и p3 = 0 + 1 + 1 = 0. Объедините данные и биты четности, и вы получите кодовое слово 0110011.

data bits   |   1 011
parity bits | 01 0
--------------------
codeword    | 0110011

Скажем, во время передачи или вычисления 6-й бит (= 3-й бит данных) переворачивается. Вы получаете слово 0110001. Предполагаемые полученные данные есть 1001. Вы снова вычислить биты четности p1 = 1 + 0 + 1 = 0, p2 = 1 + 0 + 1 = 0, p3 = 0 + 0 + 1 = 1. Соответствует только p1битам четности кодового слова 0110001. Поэтому произошла ошибка. Глядя на таблицу выше, говорит нам, что произошла ошибка, d3и вы можете восстановить исходные данные 1011.

Вызов:

Напишите функцию или программу, которая получает слово (7 бит), один из битов может быть неправильным, и восстановите исходные данные. Формат ввода (через STDIN, аргумент командной строки, приглашение или аргумент функции) может быть строкой "0110001", списком или массивом [0, 1, 1, 0, 0, 0, 1]или целым числом в MSB 0b0110001 = 49. Как описано выше, порядок ввода такой p1 p2 d1 p3 d2 d3 d4. Вывод (через возвращаемое значение или STDOUT) должен быть в том же формате, но в порядке d1 d2 d3 d4. Вернуть / вывести только 4 бита данных.

Это код-гольф. Поэтому самый короткий код выигрывает.

Тестовые случаи:

1110000 -> 1000  # no error
1100000 -> 1000  # error at 1st data bit
1111011 -> 1111  # error at 2nd data bit
0110001 -> 1011  # error at 3rd data bit (example)
1011011 -> 1010  # error at 4th data bit
0101001 -> 0001  # error at 1st parity bit
1010000 -> 1000  # error at 2nd parity bit
0100010 -> 0010  # error at 3rd parity bit

Jakube
источник
1
Есть ли конкретная причина, по которой последний бит четности задается после первого бита данных?
xnor
2
@xnor Математически это не имеет никакого значения, в каком положении находятся биты четности. Исторически они ставятся на позиции двух держав. Например, у Хэмминга (15,11) есть биты четности в позициях 1, 2, 4 и 8.
Якуб
4
@xnor Если вы берете [is_p3_wrong][is_p2_wrong][is_p1_wrong]в основу два, это дает позицию неправильного бита в слове. (На основе таблицы в вопросе.) Это, вероятно, будет полезно для некоторых алгоритмов.
рандома
Очень приятно :) Когда вы пишете «Напишите функцию или программу, которая получает слово (7 бит), один из них может быть неправильным, [...]» Я думаю, вы имеете в виду, что один из битов может быть неправильным, но вы на самом деле сказать, что одно из слов может быть.
@Lembik Конечно, уточнил.
Якуб

Ответы:

6

Октава, 70 66 55 байт

Эта функция Fустанавливает матрицу декодирования H, находит ошибку и корректирует ее положение (если оно есть). Затем он возвращает правильные биты данных. Ввод является стандартным вектором строки.

@Jakube предложил мне использовать Octave вместо Matlab, где вы можете использовать индексы для выражений, что снова делает все это короче 11 байтов:

F=@(c)xor(c,1:7==bi2de(mod(c*de2bi(1:7,3),2)))([3,5:7])

Ниже приводится самое короткое решение в Matlab , так как вы не можете напрямую использовать индексирование для выражений. (Это работает и в Octave, конечно.) Был в состоянии заменить дополнение / mod2 на xor:

f=@(c)c([3,5:7]);F=@(c)f(xor(c,1:7==bi2de(mod(c*de2bi(1:7,3),2))))

Старый:

f=@(c)c([3,5:7]);F=@(c)f(mod(c+(1:7==bi2de(mod(c*de2bi(1:7,3),2))),2))
flawr
источник
Спасибо, но это не работает, к сожалению, вы можете получить доступ только к переменным таким образом ...
flawr
1
Matlab не установлен, я использовал только там http://octave-online.net/, где он работает. Может поменять язык?
Якуб
О, я уже подозревал, что октава может это сделать, но потом я, конечно, поменяю язык, большое спасибо!
flawr
14

Пит 50х11 = 550

введите описание изображения здесь

Размер кода равен 15. Не слишком обеспокоен размером, но он прошел все тесты.

captncraig
источник
4
Мне скорее нравится это, учитывая контекст проблемы.
1
@Optimizer "codel size" - это, по сути, коэффициент увеличения программы piet. Здесь каждый логический пиксель (или кодел) был расширен до блока 15x15 для облегчения видимости. Это то, что я имею в виду, а не «размер кода»
captncraig
ах ..... мой плохой
Оптимизатор
8

Python, 79

f=lambda x,n=0,e=3:e&~-e and f(x,n+1,(n&8)*14^(n&4)*19^(n&2)*21^n%2*105^x)or~-n

Возьмите ввод и вывод как числа с младшим значащим битом справа.

Вместо того, чтобы пытаться исправить ошибки, мы просто пытаемся кодировать каждое возможное сообщение nот 0 до 15, пока не получим кодировку, которая находится на расстоянии одного бита от того, что дано. Рекурсия продолжает увеличиваться, nпока не найдет тот, который работает, и не вернет его. Хотя явного завершения нет, оно должно заканчиваться в 16 циклах.

Выражение (n&8)*14^(n&4)*19^(n&2)*21^n%2*105реализует битовую матрицу Хемминга.

Чтобы проверить наличие одной ошибки, мы зашифровываем данное сообщение с вычисленным значением eи проверяем, является ли оно степенью двойки (или 0) с помощью классического бит-трюка e&~-e==0. Но на самом деле мы не можем присвоить переменную eв лямбде, и мы ссылаемся на нее дважды в этом выражении, поэтому мы делаем хак, передавая ее в качестве необязательного аргумента следующему рекурсивному шагу.

XNOR
источник
7

JavaScript (ES6), 92 87 81

Функция получает и возвращает целое число в MSB.
Реализация проста после комментария @randomra:

  • calc p3wrong | p2wrong | p1wrong (строка 2,3,4)
  • используйте его как битовую маску, чтобы перевернуть неправильный бит (строка 1),
  • затем вернуть только биты данных (последняя строка)
F=w=>(w^=128>>(
  (w^w*2^w*4^w/2)&4|
  (w/8^w^w*2^w/16)&2|
  (w/16^w/4^w^w/64)&1
))&7|w/2&8

Тест в консоли Frefox / FireBug

;[0b1110000,0b1100000,0b1111011,0b0110001,
0b1011011,0b0101001,0b1010000,0b0100010]
.map(x=>x.toString(2)+'->'+F(x).toString(2))

Выход

["1110000->1000", "1100000->1000", "1111011->1111", "110001->1011", "1011011->1010", "101001->1", "1010000->1000", "100010->10"]
edc65
источник
1
Мне очень нравится ваше компактное побитовое решение =)
flawr
4

Python 2, 71

f=lambda i,b=3:i&7|i/2&8if chr(i)in'\0%*3<CLUZfip'else f(i^b/2,b*2)

Несколько символов являются непечатаемыми ASCII, поэтому здесь есть экранированная версия:

f=lambda i,b=3:i&7|i/2&8if chr(i)in'\0\x0f\x16\x19%*3<CLUZfip\x7f'else f(i^b/2,b*2)

Вход и выход в функцию выполняются как целые числа.

Я пользуюсь тем фактом, что количество действительных сообщений составляет всего 16, и жестко их всех кодирую. Затем я пытаюсь переворачивать разные биты, пока не получу один из них.

feersum
источник
3

Haskell, 152 байта

a(p,q,d,r,e,f,g)=b$(d+e)#p+2*(d+f)#q+4*(e+f)#r where b 3=(1-d,e,f,g);b 5=(d,1-e,f,g);b 6=(d,e,1-f,g);b 7=(d,e,f,g-1);b _=(d,e,f,g);x#y=abs$(x+g)`mod`2-y

Использование: a (1,1,1,1,0,1,1)какие выводы(1,1,1,1)

Простое решение: если p<x>не совпадает, установите бит <x>в число. Если это число 3, 5, 6или 7, флип соответствующий d<y>.

Ними
источник
Можете ли вы добавить еще несколько инструкций о том, как вызывать код (например, с помощью онлайн-компилятора, например ideone.com )? Я всегда получаю странные ошибки (скорее всего, моя вина).
Якуб
@Jakube: сохранить код в файл, скажем , hamming.hsи загрузить его в GHCI Haskell REPL: ghci hamming.hs. Вызовите функцию, aкак описано выше. Единственный известный мне онлайн-переводчик haskell ( tryhaskell.org ) требует еще немного кода:let a(p,q, ... 2-y in a (1,1,1,1,0,1,1)
nimi
3

Машинный код IA-32, 36 байтов

HexDump:

33 c0 40 91 a8 55 7a 02 d0 e1 a8 66 7a 03 c0 e1
02 a8 78 7a 03 c1 e1 04 d0 e9 32 c1 24 74 04 04
c0 e8 03 c3

Эквивалентный код C:

unsigned parity(unsigned x)
{
    if (x == 0)
        return 0;
    else
        return x & 1 ^ parity(x >> 1);
}

unsigned fix(unsigned x)
{
    unsigned e1, e2, e3, err_pos, data;
    e1 = parity(x & 0x55);
    e2 = parity(x & 0x66);
    e3 = parity(x & 0x78);
    err_pos = e1 + e2 * 2 + e3 * 4;
    x ^= 1 << err_pos >> 1;
    data = x;
    data &= 0x74;
    data += 4;
    data >>= 3;
    return data;
}

Процессор x86 автоматически вычисляет четность каждого промежуточного результата. Он имеет специальную инструкцию, jpкоторая прыгает или не прыгает в зависимости от четности.

Это не было указано явно в вызове, но удобное свойство кодов Хэмминга заключается в том, что вы можете интерпретировать биты четности как двоичное число, и это число указывает, какой бит был испорчен во время передачи. На самом деле это число основано на 1, причем 0 означает, что ошибок передачи не было. Это реализуется путем смещения 1 влево, err_posа затем вправо 1.

После исправления ошибки передачи код размещает биты данных в нужном порядке. Код оптимизирован по размеру, и поначалу может быть неясно, как он работает. Чтобы объяснить это, я обозначу через a, b, c, dбиты данных, и P, Qи Rбиты четности. Потом:

    data = x;     // d  c  b  R  a  Q  P
    data &= 0x74; // d  c  b  0  a  0  0
    data += 4;    // d  c  b  a ~a  0  0
    data >>= 3;   // d  c  b  a

Источник сборки (fastcall соглашение, с входом ecxи выходом eax):

    xor eax, eax;
    inc eax;
    xchg eax, ecx;

    test al, 0x55;
    jp skip1;
    shl cl, 1;

skip1:
    test al, 0x66;
    jp skip2;
    shl cl, 2;

skip2:
    test al, 0x78;
    jp skip3;
    shl ecx, 4;

skip3:
    shr cl, 1;
    xor al, cl;

    and al, 0x74;
    add al, 4;
    shr al, 3;

    ret;
anatolyg
источник