Виправити помилки за допомогою Хеммінга (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


1
Чи є певна причина, коли останній біт паритету надається після першого біта даних?
xnor

2
@xnor Математично це не має різниці, в якій позиції знаходяться біти парності. Історично вони розміщуються на позиціях двох. Наприклад, Хеммінг (15,11) має
парні

4
@xnor Якщо ви берете [is_p3_wrong][is_p2_wrong][is_p1_wrong]в базі два, це дає положення неправильного біта в цьому слові. (На основі таблиці у запитанні.) Це, мабуть, буде корисним для деяких алгоритмів.
randomra

Дуже приємно :) Коли ви пишете "Напишіть функцію чи програму, яка отримує слово (7 біт), один із них може бути неправильним, [...]" Я думаю, ви маєте на увазі, що один з бітів може бути неправильним, але ви насправді сказати одне зі слів може бути.

@ Лембік Звичайно, уточнив це.
Якубе

Відповіді:


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

1
Не встановлено Matlab, я використовував лише те http://octave-online.net/, де він працює. Може, змінити мову?
Якубе

О, я вже підозрював, що октава може це зробити, але тоді я, звичайно, зміню мову, дуже дякую!
недолік

14

Піт 50x11 = 550

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

розмір коделі - 15. Не надто стурбований розміром, але він пройшов усі тести.


4
Мені це подобається, враховуючи контекст проблеми.

1
@Optimizer "розмір коделі" - це, по суті, коефіцієнт збільшення програми піт. Тут кожен логічний піксель (або кодекс) був розширений до блоку 15х15 для полегшення видимості. Це те, що я маю на увазі, а не "розмір коду"
captncraig

ах ..... моя погана.
Оптимізатор

8

Пітона, 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в межах лямбда, і ми посилаємось на неї двічі в цьому виразі, тому ми робимо хак передачі її як необов'язковий аргумент до наступного рекурсивного кроку.


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"]

1
Мені дуже подобається ваше компактне побітове рішення =)
недолік

4

Пітон 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, і жорстко кодую їх усі. Потім я намагаюся гортати різні шматочки, поки я не отримаю один із таких.


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і завантажте його в Haskell REPL ghci : ghci hamming.hs. Викличте функцію, aяк описано вище. Єдиний мені інтерпретатор haskell, про якого я знаю ( tryhaskell.org ), потребує ще коду:let a(p,q, ... 2-y in a (1,1,1,1,0,1,1)
німі

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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.