Manchester mã hóa một luồng dữ liệu


14

Mã hóa Manchester là một giao thức viễn thông được sử dụng trong thông tin vô tuyến đảm bảo chuyển đổi bit theo chu kỳ đều đặn để người nhận có thể khôi phục tốc độ xung nhịp từ chính dữ liệu. Nó tăng gấp đôi bitrate, nhưng rẻ và đơn giản để thực hiện. Nó được sử dụng rộng rãi bởi các nhà khai thác vô tuyến nghiệp dư.

Khái niệm này rất đơn giản: ở cấp độ phần cứng, đồng hồ và các dòng dữ liệu chỉ đơn giản là XOR với nhau. Trong phần mềm, điều này được mô tả là chuyển đổi một luồng bit đầu vào thành luồng đầu ra có tốc độ gấp đôi, với mỗi đầu vào '1' được dịch thành '01' và mỗi đầu vào '0' được dịch thành '10'.

Đây là một vấn đề dễ dàng, nhưng mở ra cho rất nhiều triển khai vì tính chất dòng bit của nó. Nghĩa là, mã hóa về mặt khái niệm là một quá trình từng bit thay vì một quá trình theo từng byte. Vì vậy, tất cả chúng ta đều đồng ý về tuổi thọ, các bit có trọng số thấp nhất của đầu vào trở thành byte ít quan trọng nhất của đầu ra.

Giờ chơi gôn! Viết một hàm, được cung cấp một mảng byte có độ dài tùy ý, trả về một mảng dữ liệu manchester được mã hóa.

Đầu vào và đầu ra nên được coi là đầu cuối nhỏ, byte đầu tiên ít quan trọng nhất và BIT ít quan trọng nhất trước tiên trong luồng bit.

Bản vẽ dòng 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

Ví dụ :

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]

Quy tắc :

  • Giải pháp chỉ yêu cầu thuật toán để chuyển đổi đầu vào thành đầu ra.
  • Có được đầu vào và đầu ra in KHÔNG phải là một phần bắt buộc của giải pháp, nhưng có thể được bao gồm. Bạn được khuyến khích cung cấp mã kiểm tra / in nếu không có trong giải pháp của bạn.
  • Đầu vào là một mảng gồm các byte 8 bit (bất cứ điều gì có thể có nghĩa trong ngôn ngữ bạn chọn), KHÔNG phải là một chuỗi văn bản. Bạn có thể sử dụng các chuỗi làm định dạng lưu trữ nếu thuận tiện trong ngôn ngữ của bạn, nhưng phải hỗ trợ các ký tự không in được (ví dụ 0xFF). Đầu vào cũng có thể mất một chiều dài nếu cần thiết.
  • Bộ nhớ cho đầu ra phải được phân bổ theo thói quen của bạn, không được cung cấp. chỉnh sửa: yêu cầu không cần thiết
  • Đầu ra cũng là một mảng gồm 8 bit byte và độ dài nếu cần thiết.
  • Phải hỗ trợ ít nhất 16KB đầu vào
  • Hiệu suất không được quá kinh khủng: <10 giây cho 16KB
  • Ít nhất là byte đáng kể đầu tiên trong bộ nhớ.

Thử thách kênh phụ :

  • Thách thức câu trả lời của người dùng khác bằng cách chứng minh mã của bạn nhanh hơn, hiệu quả bộ nhớ hơn hoặc tạo ra một nhị phân nhỏ hơn!

Nhận chơi gôn! Mã ngắn nhất sẽ thắng!


2
"Bộ nhớ cho đầu ra phải được phân bổ theo thói quen của bạn, không được cung cấp." Đó dường như là một yêu cầu khá kỳ lạ vì nhiều ngôn ngữ có phân bổ bộ nhớ hoàn toàn tự động.
aaaaaaaaaaaa

Điều gì trên trái đất sở hữu bạn để sử dụng một thứ tự bit kỳ quái như vậy?
Peter Taylor

Thứ tự bit có ý nghĩa khi bạn xem xét phương tiện vật lý này được sử dụng cho; thuật toán này dành cho một luồng các bit riêng lẻ truyền qua không khí. Thực tế là chúng ta phải lưu trữ nó trong bộ nhớ và chúng ta viết hex msb-> lsb, làm cho nó hơi khó để theo dõi.
mrmekon

Câu trả lời:


6

GolfScript 28 ký tự

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

Phiên bản tương đương mà không tối ưu hóa obfuscating:

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

Mã chấp nhận đầu vào dưới dạng một mảng các số nguyên và trả về ditto.

Đối với mỗi số trong mảng, số được chuyển đổi thành dạng mảng cơ sở 2, sau đó nó được chuyển đổi trở lại thành một số như thể nó là cơ sở 4, điều này có tác dụng cách nhau các bit với 0 ở giữa mỗi bit. 43691 sau đó được trừ vào số và kết quả là đảo ngược nhị phân, điều này tương đương với việc trừ số từ 43690 (43690 = 0b1010101010101010). Số này sau đó được chia thành hai phần bằng cách chuyển đổi nó thành một mảng cơ sở 256, mảng bị phân tách và thứ tự của hai số kết quả được đảo ngược.

Ví dụ đầu vào:

[1 2 3 241 242 243]

Ví dụ đầu ra:

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

Điều đó thật lố bịch và rất thông minh! Mặc dù nó dường như không đáp ứng 16KB trong đề xuất hiệu suất <10 giây, ít nhất là đối với tôi; máy của bạn mất 43 giây trên máy Mac lõi kép của tôi để chuyển đổi một mảng 16384 1 '. Để so sánh, việc thực hiện con trăn khổng lồ (2419 char) của tôi mất 0,06 giây cho 16KB.
mrmekon

Mất ít hơn 5 giây trên máy của tôi (Win 7) và hầu hết trong số đó là chuyển đổi mảng thành đầu ra văn bản, theo như tôi đọc câu hỏi của bạn không phải là một phần của yêu cầu, nhưng GolfScript tự động làm như vậy với mọi thứ còn lại trên ngăn xếp sau khi thực hiện. Người ta có thể chỉ cần làm cho mã giảm kết quả thay vì in nó (thêm; vào cuối mã). Nếu bạn muốn xem đầu ra (mặc dù đó không phải là một phần của thông số kỹ thuật câu hỏi.) Tôi biết hai thủ thuật để tăng tốc độ, chuyển hướng nó đến một tệp và in rõ ràng trong các đoạn nhỏ bằng cách sử dụng lệnh in:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

Trong một ubfox vm (trên windows), tôi nhận được 8 giây với giá 16kb. Trên máy mac có cpu tốt hơn, nó mất 1m18. Tôi đoán viên ruby ​​hơn tàu có OSX thì cực kỳ chậm
gnibbler

Có vẻ như việc in ruby ​​chậm kinh khủng trên máy của tôi. Chỉ 2 giây với in ấn tắt và Ruby 1.9 (và 5s với phiên bản OSX gốc). Điều đó tốt hơn nhiều!
mrmekon

3

c - 224 ký tự

Tôi tin rằng đây là chức năng, bao gồm cả việc phân bổ yêu cầu bộ nhớ kể từ khi bỏ.

#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;}

Phần làm việc của mã là một vòng lặp trên các bit của mỗi ký tự, lưu ý rằng ((bit + 1) độc quyền - hoặc 3) là cặp bit đầu ra và áp dụng rất nhiều logic dịch chuyển và mặt nạ để sắp xếp mọi thứ.

Như c của wont, nó hoạt động trên dữ liệu dưới dạng các ký tự. Giàn giáo thử nghiệm sẽ không chấp nhận 0 byte (vì c coi chúng là kết thúc chuỗi), nhưng mã làm việc không có giới hạn như vậy.

Nó có thể được đánh gôn nhiều hơn bằng cách sao chép nội tuyến chuyển đổi byte.

Chạy thử (với giàn giáo thử nghiệm được cải thiện):

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

Nhận xét, ít phụ thuộc máy hơn và với giàn giáo thử nghiệm

/* 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)

Đề cương giải thích (Xem Từ vựng J để tham khảo):

  • ,@:(3 :'...'"0)áp dụng ... cho mỗi "byte" đầu vào là y, dẫn đến hai byte (số nguyên) mỗi đầu vào. Kết quả được làm phẳng bởi ,.
  • y#:~8#2tương đương với 2 2 2 2 2 2 2 2 #: yhoặc vectơ của 8 chữ số cơ bản có ý nghĩa nhỏ nhất của y.
  • 4|. hoán đổi 4 bit trước và sau bằng cách xoay 4 vị trí.
  • (,.~-.)tương đương 3 :'(-. y) ,. y'hoặc không với đối số 'được khâu' với đối số (lấy hình 8 2).
  • #.2 8$, làm phẳng kết quả cho dòng bit, định hình lại thành 2 hàng 8 và chuyển đổi từ cơ sở 2.

Ví dụ sử dụng (J, tương tác):

    ,@:(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

Thông tin tốc độ (J, tương tác):

   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

Thời gian trung bình cho 16kb chỉ dưới 0,25 giây, Intel Core Duo 1,83Ghz hoặc tương tự.


3

Haskell, 76 ký tự

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

Chạy thử:

> 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

Hiệu suất là tốt trong spec. ở mức 1MB trong ~ 1,2 giây trên máy tính xách tay cũ của tôi. Nó bị ảnh hưởng bởi vì đầu vào được chuyển đổi thành và từ một danh sách, sau đó được xử lý như một 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

Nguồn, 2040-Manchester.hs , bao gồm mã, kiểm tra và chức năng chính cho bộ lọc dòng lệnh.


3

Pin OCaml +, 138 117 ký tự

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]?]))

Các xét nghiệm:

Với

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

Kết quả là:

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"

Là một điểm chuẩn, với:

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

Tôi có:

# benchmark 16_384;;
- : float = 0.115520954132080078

trên MacBook của tôi.


1

Python, 87 ký tự

Mlà chức năng được yêu cầu trong bài toán. Nó gọi Ncho mỗi nybble và chia mọi thứ lại thành một danh sách.

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

tạo ra

['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 byte

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

Hãy thử trực tuyến!

Cổng của câu trả lời 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 byte

Lấy một loạt các byte hex và chuyển đổi thành luồng nhị phân manchester.

#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");}}

Kiểm tra:

./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

Đầu ra:

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

Bộ tạo dữ liệu thử nghiệm 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

Thử nghiệm thời gian cốt lõi 1.6G i5dual:

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

Bài đăng đầu tiên rất hay, nhưng chúng tôi thường không cố gắng làm xáo trộn mã của chúng tôi. Có ngắn hơn, khó đọc hơn không.
Rɪᴋᴇʀ

0

PHP, 156 byte

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;}

Đưa ra đầu vào [0, 1, 2, 3, 4, 5], nó trả về:

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

Nó mã hóa 16 KiB dữ liệu trong 0,015 giây và 1 MiB dữ liệu trong khoảng 0,9 giây.

Mã không mã hóa, một triển khai khác (dài hơn và chậm hơn khoảng hai lần) và các trường hợp thử nghiệm có thể được tìm thấy trên trang giải pháp mã golf của tôi trên Github.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.