맨체스터는 데이터 스트림을 인코딩


14

맨체스터 코딩 은 무선 통신에 사용되는 통신 프로토콜로, 수신기는 데이터 자체에서 클럭 속도를 복구 할 수 있도록 일정한 간격으로 비트 전환을 보장합니다. 비트 전송률을 두 배로 늘리지 만 구현하기가 저렴하고 간단합니다. 아마추어 무선 통신 사업자가 널리 사용합니다.

개념은 매우 간단합니다. 하드웨어 수준에서 클럭과 데이터 라인은 단순히 XOR됩니다. 소프트웨어에서 이것은 비트의 입력 스트림을 이중 속도 출력 스트림으로 변환하는 것으로 묘사되며, 각 입력 '1'은 '01'로 변환되고 각 입력 '0'은 '10'으로 변환됩니다.

이것은 쉬운 문제이지만 비트 스트림 특성으로 인해 많은 구현에 개방적입니다. 즉, 인코딩은 개념적으로 바이트 단위 프로세스 대신 비트 단위 프로세스입니다. 따라서 우리 모두 엔디안에 동의합니다. 입력의 최하위 비트가 출력의 최하위 바이트가됩니다.

골프 시간! 임의의 길이의 바이트 배열이 주어진 경우 해당 데이터의 맨체스터 인코딩 된 배열을 반환하는 함수를 작성하십시오.

입력 및 출력은 비트 스트림에서 리틀 엔디안, 최하위 바이트 우선 및 최하위 BIT 우선으로 간주되어야합니다.

ASCII 비트 스트림 그리기 :

bit #      5 4 3 2 1 0                                5  4  3  2  1  0
IN ------- 1 0 1 0 1 1 ---> [manchester encoder] ---  01 10 01 10 01 01 ----> OUT

:

Example 1 (hex):
       LSB              MSB     <-- least sig BYTE first
IN : [0x10, 0x02]  
OUT: [0xAA, 0xA9, 0xA6, 0xAA]  

Example 1 (binary):
      msb  lsb                      msb  lsb  <-- translated hex, so msb first
BIN: [00010000, 00000010]                     <-- least sig NIBBLE...
BIN: [10101010, 10101001, 10100110, 10101010] <-- becomes least sig BYTE
         LSB                           MSB

Example 2
IN :  [0xFF, 0x00, 0xAA, 0x55]  
OUT: [0x55, 0x55, 0xAA, 0xAA, 0x66, 0x66, 0x99, 0x99]

Example 3
IN : [0x12, 0x34, 0x56, 0x78, 0x90]  
OUT: [0xA6, 0xA9, 0x9A, 0xA5, 0x96, 0x99, 0x6A, 0x95, 0xAA, 0x69] 

Example 4
IN : [0x01, 0x02, 0x03, 0xF1, 0xF2, 0xF3]  
OUT: [0xA9, 0xAA, 0xA6, 0xAA, 0xA5, 0xAA, 0xA9, 0x55, 0xA6, 0x55, 0xA5, 0x55]

규칙 :

  • 솔루션은 입력을 출력으로 변환하는 알고리즘 만 필요합니다.
  • 입력 및 인쇄 출력을 얻는 것이 솔루션의 필수 부분은 아니지만 포함될 수 있습니다. 솔루션에 포함되지 않은 경우 테스트 / 인쇄 코드를 제공하는 것이 좋습니다.
  • 입력은 텍스트 문자열이 아닌 8 비트 바이트 (선택한 언어에 따라 다름)의 배열입니다. 언어가 편리한 경우 문자열을 저장 형식으로 사용할 수 있지만 인쇄 할 수없는 문자 (예 : 0xFF)가 지원되어야합니다. 필요한 경우 입력 시간도 길어질 수 있습니다.
  • 출력용 메모리는 제공되지 않은 루틴에 의해 할당되어야합니다. 편집 : 불필요한 요구 사항
  • 출력은 또한 8 비트 바이트의 배열이며 필요한 경우 길이입니다.
  • 16KB 이상의 입력을 지원해야합니다
  • 16KB의 경우 <10s
  • 메모리에서 최하위 바이트.

부 채널 챌린지 :

  • 코드가 더 빠르고, 메모리 효율적이거나, 더 작은 바이너리를 생성하여 다른 사용자의 답변에 도전하십시오!

골프를 타십시오! 최단 코드 승리!


2
"출력용 메모리는 제공되지 않은 루틴에 의해 할당되어야합니다." 많은 언어가 완전히 자동 메모리 할당을 가지고 있기 때문에 이것은 꽤 이상한 요구 사항처럼 보입니다.
aaaaaaaaaaaa

지구상에서 당신이 그런 기괴한 비트 순서를 사용하도록 당신을 품은 것은 무엇입니까?
피터 테일러

비트 순서는 이것이 사용되는 물리적 매체를 고려할 때 의미가 있습니다. 이 알고리즘은 공기를 통해 이동하는 개별 비트 스트림을위한 것입니다. 메모리에 저장해야하고 16 진수 msb-> lsb를 작성한다는 사실을 추적하기가 약간 까다로워집니다.
mrmekon

답변:


6

GolfScript 28 자

{2{base}:|~4|43691-~256|~\}%

난독 화 최적화가없는 동등한 버전 :

{2base 4base 43691-~256base~\}%

이 코드는 입력을 정수 배열로 받아들이고 ditto를 반환합니다.

배열의 각 숫자에 대해 숫자는 밑이 2 인 배열 형식으로 변환 된 다음 밑이 4 인 것처럼 숫자로 다시 변환됩니다. 이는 각각 사이에 0이있는 비트의 간격을 두는 효과가 있습니다. 그런 다음 43691은 숫자에서 빼고 결과는 2 진 반전되며 43690에서 숫자를 빼는 것과 같습니다 (43690 = 0b1010101010101010). 그런 다음 숫자를 기본 256 배열로 변환하여 두 부분으로 나누고 배열을 분해하고 결과 숫자의 순서를 반대로합니다.

입력 예 :

[1 2 3 241 242 243]

출력 예 :

[169 170 166 170 165 170 169 85 166 85 165 85]

엄청나게 짧고 매우 영리합니다! 적어도 10 초 미만의 성능 제안에서 16KB를 충족시키지 못하는 것 같습니다. 내 듀얼 코어 Mac에서 43을 사용하여 16384 1의 배열을 변환하십시오. 반면에, 대규모 (2419 문자) 파이썬 구현은 16KB에 0.06 초가 걸립니다.
mrmekon

내 컴퓨터 (Win 7)에서 5 초도 걸리지 않으며 대부분은 배열을 텍스트 출력으로 변환합니다. 질문을 읽는 한 요구 사항의 일부는 아니지만 GolfScript는 남은 모든 것을 자동으로 수행합니다. 실행 후 스택에. 코드를 인쇄하지 않고 결과를 떨어 뜨릴 수 있습니다 (코드 끝에 추가;). 출력을보고 싶다면 (질문 스펙의 일부는 아니지만) 속도를 높이고 파일로 리디렉션하고 인쇄 명령을 사용하여 작은 덩어리로 명시 적으로 인쇄하는 두 가지 방법을 알고 있습니다.{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

우분투 vm (Windows)에서 16kb에 대해 8 초를 얻습니다. 더 나은 CPU를 가진 Mac에서는 1m18이 걸렸습니다. OSX 그냥 끔찍하게 느린와 나는 배보다 루비를 추측에는 요
gnibbler

내 기계에서 루비 인쇄가 역겨운 것처럼 보입니다. 인쇄가 해제 된 상태에서 2 초만, Ruby 1.9 (및 고유 OSX 버전의 경우 5 초) 훨씬 낫다!
mrmekon

3

c-224 자

삭제 이후 메모리 요구 사항 할당을 포함하여 이것이 기능적이라고 생각합니다.

#include <stdlib.h>
int B(char i){int16_t n,o=0xFFFF;for(n=0;n<8;++n)o^=((((i>>n)&1)+1))<<(2*n);
return o;}char* M(char*i,int n){char*o=calloc(n+1,2),*p=o;do{int r=B(*i++);
*p++=0xFF&r;*p++=(0xFF00&r)>>8;}while(--n);return o;}

코드의 작업 부분은 ((bit + 1) 배타적 또는 3)이 출력 비트 쌍임을 지적하고 모든 시프트 및 마스킹 논리를 적용하여 모든 것을 정렬하도록 각 문자의 비트를 반복합니다.

c와 마찬가지로 데이터에서 문자로 작동합니다. 테스트 스캐 폴드는 0 바이트 (c는 문자열 끝으로 취급하기 때문에)를 허용하지 않지만 작업 코드에는 그러한 제한이 없습니다.

바이트 변환 작업을 인라인으로 복사하면 조금 더 골프를 칠 수 있습니다.

테스트 실행 (테스트 스캐 폴드 개선) :

$ gcc -g manchester_golf.c
$ ./a.out AB xyz U
'AB':
[ 0x41, 0x42 ]
[ 0xa9, 0x9a, 0xa6, 0x9a ]
'xyz':
[ 0x78, 0x79, 0x7a ]
[ 0x6a, 0x95, 0x69, 0x95, 0x66, 0x95 ]
'U':
[ 0x55 ]
[ 0x99, 0x99 ]

주석 처리, 기계 의존성이 적으며 테스트 스캐 폴드

/* manchester.c
 *
 * Manchester code a bit stream least significant bit first
 *
 * Manchester coding means that bits are expanded as {0,1} --> {10, 01}
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>

/* Caller must insure that out points to a valid, writable two byte
   buffer filled with 0xFF */
int16_t manByte(char i){
  int16_t n,o=0xFFFF;
  printf("Manchester coding byte 0x%hx...\n",i);
  for(n=0; n<CHAR_BIT; ++n)
    o ^= (
      (
       (
        (i>>n)&1) /* nth bit of i*/
       +1) /* +1 */
      ) <<(2*n) /* shifted up 2*n bits */ 
      ;
  printf("\tas 0x%hx\n",o);
  return o;
}

char* manBuf(const char*i, int n){
  char*o=calloc(n+1,2),*p=o;
  do{
    int16_t r=manByte(*i++);
    *p++= 0xFF&r;
    *p++=(0xFF00&r)>>8;
  } while(--n);
  return o;
}

void pbuf(FILE* f, char *buf, int len){
  int i;
  fprintf(f,"[");
  for(i=0; i<len-1; i++)
    fprintf(f," 0x%hhx,",buf[i]);
  fprintf(f," 0x%hhx ]\n",buf[len-1]);
}

int main(int argc, char**argv){
  int i;
  for(i=1; i<argc; i++){
    int l=strlen(argv[i]);
    char *o=manBuf(argv[i],l);
    printf("'%s':\n",argv[i]);
    pbuf(stdout,argv[i],l);
    pbuf(stdout,o,l*2);
    free(o);
  }
  return 0;
}

3

J, 36

,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)

설명 개요 (참조를 위해 J 어휘 참조) :

  • ,@:(3 :'...'"0)...를 각 입력 "byte"에 y로 적용하여 각각 2 바이트 (정수)를 생성합니다. 결과는로 평탄화됩니다 ,.
  • y#:~8#22 2 2 2 2 2 2 2 #: y또는 y의 8 자리 최하위 2 자리의 벡터 와 같습니다 .
  • 4|. 4 개의 위치로 회전하여 앞뒤 4 비트를 바꿉니다.
  • (,.~-.)3 :'(-. y) ,. y'인수에 '스티치 된'인수 와 같 거나 같지 않습니다 (형상 8 2를 취함).
  • #.2 8$, 결과를 평평하게하여 비트 스트림을 제공하고 8의 2 행으로 모양을 바꾼 다음 기본 2에서 변환합니다.

사용법 예 (J, 대화식) :

    ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0) 1 2 3 241 242 243
,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0) 1 2 3 241 242 243
169 170 166 170 165 170 169 85 166 85 165 85

속도 정보 (J, 대화식) :

   manchester =: ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)
manchester =: ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)
   data =: 256 | i. 16384
data =: 256 | i. 16384
   100 (6!:2) 'manchester data'
100 (6!:2) 'manchester data'
0.243138

16kb의 평균 시간은 .25 초, Intel Core Duo 1.83Ghz 또는 그 이하입니다.


3

하스켈, 76 자

import Bits
z a=170-sum[a.&.p*p|p<-[1,2,4,8]]
y a=[z a,z$a`div`16]
m=(>>=y)

시운전 :

> testAll 
input      [10, 02]
encoded    [AA, A9, A6, AA]
  pass
input      [FF, 00, AA, 55]
encoded    [55, 55, AA, AA, 66, 66, 99, 99]
  pass
input      [12, 34, 56, 78, 90]
encoded    [A6, A9, 9A, A5, 96, 99, 6A, 95, AA, 69]
  pass
input      [01, 02, 03, F1, F2, F3]
encoded    [A9, AA, A6, AA, A5, AA, A9, 55, A6, 55, A5, 55]
  pass

성능은 사양 내에 있습니다. 내 오래된 랩톱에서 ~ 1.2 초에 1MB로. 입력이 목록으로 변환되거나 목록에서 변환되기 때문에 문제가 발생합니다 ByteArray.

> dd bs=1m count=1 if=/dev/urandom | time ./2040-Manchester > /dev/null
1+0 records in
1+0 records out
1048576 bytes transferred in 1.339130 secs (783028 bytes/sec)
        1.20 real         1.18 user         0.01 sys

소스 2040-Manchester.hs 에는 명령 줄 필터의 코드, 테스트 및 주요 기능이 포함되어 있습니다.


3

OCaml + 배터리, 138117

let m s=Char.(String.(of_enum[?chr(170-Enum.sum[?d land
p*p|p<-List:[1;2;4;8]?])|c<-enum s/@code;d<-List:[c;c/16]?]))

테스트 :

let hex s = String.(enum s/@(Char.code|-Printf.sprintf "%02x")|>List.of_enum|>join" ")

결과는 다음과 같습니다.

m "\x12\x34\x56\x78\x90" |> hex;;
- : string = "a6 a9 9a a5 96 99 6a 95 aa 69"
m "\x10\x02" |> hex;;
- : string = "aa a9 a6 aa"
m "\xFF\x00\xAA\x55" |> hex;;
- : string = "55 55 aa aa 66 66 99 99"
m "\x12\x34\x56\x78\x90" |> hex;;
- : string = "a6 a9 9a a5 96 99 6a 95 aa 69"
m "\x01\x02\x03\xF1\xF2\xF3" |> hex;;  
- : string = "a9 aa a6 aa a5 aa a9 55 a6 55 a5 55"

다음과 같은 기준으로 :

let benchmark n =
  let t = Unix.gettimeofday() in
  assert(2*n == String.(length (m (create n))));
  Unix.gettimeofday() -. t

나는 얻다:

# benchmark 16_384;;
- : float = 0.115520954132080078

내 MacBook에서


1

파이썬, 87 자

M문제에서 요청한 기능입니다. 그것은 N각각의 nybble을 요구하고 모든 것을 목록으로 다시 연결합니다.

N=lambda x:170-(x&1|x*2&4|x*4&16|x*8&64)
M=lambda A:sum([[N(a),N(a>>4)]for a in A],[])

print map(hex,M([0x10,0x02]))
print map(hex,M([0xff,0x00,0xaa,0x55]))
print map(hex,M([0x12, 0x34, 0x56, 0x78, 0x90]))
print map(hex,M([0x01, 0x02, 0x03, 0xF1, 0xF2, 0xF3]))

생성

['0xaa', '0xa9', '0xa6', '0xaa']
['0x55', '0x55', '0xaa', '0xaa', '0x66', '0x66', '0x99', '0x99']
['0xa6', '0xa9', '0x9a', '0xa5', '0x96', '0x99', '0x6a', '0x95', '0xaa', '0x69']
['0xa9', '0xaa', '0xa6', '0xaa', '0xa5', '0xaa', '0xa9', '0x55', '0xa6', '0x55', '0xa5', '0x55']

1

APL (Dyalog Extended) , 22 바이트

∊(⌽(2256)⊤43690-4⊥⊤)¨

온라인으로 사용해보십시오!

GolfScript 답변 포트.

∊(⌽(2256)⊤43690-4⊥⊤)¨       Monadic train:
  ⌽(2256)⊤43690-4⊥⊤         Define a helper function taking an integer n:
                               Convert n to base 2. Monadic  is an Extended feature.
                  4            Convert the result from base 4.
                                This puts the 1 digits of n 
                                in odd indices of the intermediate result.
            43960-              Subtract from 43690.
    (2256)⊤                    Convert to 2 base-256 digits, corresponding to
                                nibbles of n.
                              Reverse the order of these bytes.
 (                          Call the helper function for each element of the input
                             and flatten the results into a list.

0

C, 164 바이트

일련의 16 진 바이트를 가져 와서 맨체스터 이진 스트림으로 변환합니다.

#include <stdio.h>
main(int c,char **v){int i,b,x,j=0;while(++j<c{sscanf(v[j],"%x",&b);x=b^0xff;for(i=9;--i;){printf("%d%d",x&1,b&1);x=x>>1;b=b>>1;}printf("\n");}}

#include <stdio.h>
main(int c,char **v){
int i,b,x,j=0;
while(++j<c){
    sscanf(v[j],"%x",&b);
    x=b^0xff;
    for(i=9;--i;){
        printf("%d%d",x&1,b&1);
        x=x>>1;b=b>>1;}
    printf("\n");}}

테스트:

./a.out 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0

산출:

1010101010101010
0110101010101010
1001101010101010
0101101010101010
1010011010101010
0110011010101010
1001011010101010
0101011010101010
1010100110101010
0110100110101010
1001100110101010
0101100110101010
1010010110101010
0110010110101010
1001010110101010
0101010110101010
1010101010101010
1010101001101010
1010101010011010
1010101001011010
1010101010100110
1010101001100110
1010101010010110
1010101001010110
1010101010101001
1010101001101001
1010101010011001
1010101001011001
1010101010100101
1010101001100101
1010101010010101
1010101001010101

16kb 테스트 데이터 세트 생성기 :

test_data.c :

#include <stdio.h>
void main()
{
int i=16*1024;
while(i--)
{
    printf("0x%02x ", i&0xFF);
}
printf("\n");
}

cc test_data.c -o test_data

1.6G i5dual 핵심 시간 시험 :

time ./a.out `./test_data` > test.out 
real    0m0.096s
user    0m0.090s
sys 0m0.011s

좋은 첫 번째 게시물이지만 일반적으로 코드를 난독 화하려고 시도하지 않습니다. 더 짧아요, 읽기가 더 어렵습니다.
Rɪᴋᴇʀ

0

PHP, 156 바이트

function f($i){foreach($i as$n){$b=str_split(str_replace([0,1,2],[2,'01',10],
str_pad(decbin($n),8,0,0)),8);$o[]=bindec($b[1]);$o[]=bindec($b[0]);}return$o;}

입력이 주어지면 다음 [0, 1, 2, 3, 4, 5]을 반환합니다.

[170, 170, 169, 170, 166, 170, 165, 170, 154, 170, 153, 170]

약 0.01 초에 16KiB의 데이터를 약 0.9 초에 1MiB의 데이터로 인코딩합니다.

Ungolfed 코드, 또 다른 구현 (길고 약 2 배 느림) 및 테스트 사례는 Github의 코드 골프 솔루션 페이지 에서 확인할 수 있습니다 .

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