해밍 (7,4)을 사용한 오류 수정


19

Hamming (7,4) 코드는 1950 년으로 거슬러 올라갑니다. 당시 Richard Hamming은 Bell Labs에서 수학자로 일했습니다. 매주 금요일 Hamming은 계산 기계가 일련의 계산을 수행하도록 설정하고 다음 월요일에 결과를 수집했습니다. 패리티 검사를 사용하여이 기계는 계산 중에 오류를 감지 할 수있었습니다. 좌절 한 그는 오류 메시지를 너무 자주 받았기 때문에 오류 감지를 개선하기로 결정하고 유명한 해밍 코드를 발견했습니다.

해밍의 역학 (7,4)

해밍 코드의 목적은 데이터 비트 또는 패리티 비트에서 단일 비트 에러 (1 비트가 뒤집어 짐)가 검출되고 정정 될 수 있도록 중첩되는 패리티 비트 세트를 생성하는 것이다. 여러 오류가 발생하는 경우에만 해밍 코드가 원본 데이터를 복구하지 못합니다. 전혀 오류가 발생하지 않거나 잘못 정정 할 수도 있습니다. 따라서이 과제에서는 단일 비트 오류 만 처리합니다.

해밍 코드의 예로 해밍 (7,4) 코드를 살펴 보겠습니다. 또한 4 비트의 데이터에 d1, d2, d3, d43 개의 패리티 비트를 사용하는데 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 = 1p3 = 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, 명령 행 인수, 프롬프트 또는 함수 인수를 통한 입력 형식은 MSB 의 문자열 "0110001", 목록 또는 배열 [0, 1, 1, 0, 0, 0, 1]또는 정수일 수 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 수학적으로는 패리티 비트가있는 위치에서 차이를 만들지 않습니다. 역사적으로 그들은 2의 거듭 제곱의 위치에 놓여 있습니다. 예를 들어 해밍 (15,11)은 위치 1, 2, 4 및 8에 패리티 비트를 가지고 있습니다.
Jakube

4
@xnor [is_p3_wrong][is_p2_wrong][is_p1_wrong]베이스 2를 받으면 단어에서 잘못된 비트의 위치를 ​​제공합니다. (문제의 표를 기반으로 함) 아마도 일부 알고리즘에 유용 할 것입니다.
randomra

아주 좋은 :) 당신이 "함수 (7 비트)를받는 함수 나 프로그램을 쓸 때, 그들 중 하나는 틀렸을 수도 있습니다. [...]" 실제로 단어 중 하나라고 말할 수 있습니다.

@Lembik Sure, 분명히했습니다.
Jakube 2019

답변:


6

옥타브, 70 66 55 바이트

이 함수 F는 디코딩 매트릭스를 설정 H하여 오류를 찾고 오류의 위치를 ​​수정합니다 (있는 경우). 그런 다음 올바른 데이터 비트를 반환합니다. 입력은 표준 행 벡터입니다.

@Jakube는 Matlab 대신 Octave를 사용하여 표현식에 인덱스를 사용할 있다고 제안했습니다 . 이는 전체를 11 바이트 더 짧게 만듭니다.

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

다음은 식에서 인덱싱을 직접 사용할 수 없으므로 Matlab 에서 가장 짧은 솔루션입니다 . (이것은 물론 Octave에서도 작동합니다.) addition / 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/작동하는 곳 에서만 사용 했습니다. 어쩌면 언어를 바꾸시겠습니까?
Jakube

오타 브는 옥타브가 그렇게 할 수 있다는 것을 이미 의심했지만, 물론 언어를 바꿀 것입니다. 대단히 감사합니다!
flawr

14

피펫 50x11 = 550

여기에 이미지 설명을 입력하십시오

코덱 크기는 15입니다. 크기에 대해서는 너무 걱정하지 않지만 모든 테스트를 통과했습니다.


4
오히려 문제의 맥락에서 이것을 좋아합니다.

1
@Optimizer "코덱 크기"는 기본적으로 piet 프로그램의 배율입니다. 여기에서 각 논리 픽셀 (또는 코덱)은 가시성을 높이기 위해 15x15 블록으로 확장되었습니다. 이것이 바로 "코드 크기"가 아니라 의미입니다.
captncraig

아 ..... 내 나쁜.
Optimizer

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주어진 비트에서 1 비트 떨어진 인코딩을 얻을 때까지 0에서 15까지 가능한 모든 메시지 를 인코딩하려고 시도합니다 . 재귀 n는 작동하는 것을 찾아서 반환 할 때까지 계속 증가 합니다. 명시적인 종료는 없지만 16 루프 내에서 끝나야합니다.

이 식은 (n&8)*14^(n&4)*19^(n&2)*21^n%2*105해밍 행렬을 비트 단위로 구현합니다.

단일 오류를 확인하기 위해 주어진 메시지를 계산할 메시지로 xor e하고 고전적인 bit-trick으로 2의 거듭 제곱인지 확인합니다 e&~-e==0. 그러나 실제로 e람다 내 에서 변수에 할당 할 수 없으며이 표현식에서 변수 를 두 번 참조하므로 다음 재귀 단계에 대한 선택적 인수로 변수를 전달합니다.


7

자바 스크립트 (ES6), 92 87 81

MSB에서 정수를 가져오고 반환하는 함수.
구현은 @randomra 주석에 따라 간단합니다.

  • 계산 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
나는 당신의 소형 비트 연산 솔루션을 정말 좋아합니다 =)
flawr

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

하스켈, 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

@Jakube : 코드를 파일에 저장하고 hamming.hsHaskell REPL ghci :로로드하십시오 ghci hamming.hs. a위에서 설명한대로 함수 를 호출하십시오 . 내가 아는 유일한 온라인 하스켈 인터프리터 ( tryhaskell.org )에는 더 많은 코드가 필요합니다.let a(p,q, ... 2-y in a (1,1,1,1,0,1,1)
nimi

3

IA-32 기계 코드, 36 바이트

16 진 덤프 :

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 CPU는 각 중간 결과의 패리티를 자동으로 계산합니다. jp패리티에 따라 점프하거나 점프하지 않는 전용 명령 이 있습니다.

챌린지에서는 명시 적으로 지정되지 않았지만 해밍 코드의 편리한 속성은 패리티 비트를 이진 숫자로 해석 할 수 있다는 것입니다.이 숫자는 전송 중 손상된 비트를 나타냅니다. 실제로이 숫자는 1을 기준으로하며 0은 전송 오류가 없음을 의미합니다. 이것은 1을 왼쪽으로 이동 err_pos한 다음 오른쪽으로 이동하여 구현 됩니다 1.

전송 오류를 수정 한 후 코드는 필요한 순서로 데이터 비트를 정렬합니다. 코드는 크기에 최적화되어 있으며 처음에는 작동 방식이 명확하지 않을 수 있습니다. 이를 설명하기 위해, I는로 나타내고 a, b, c, d데이터 비트 및에 의해 P, QR패리티 비트. 그때:

    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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.