แมนเชสเตอร์เข้ารหัสกระแสข้อมูล


14

การเข้ารหัสแมนเชสเตอร์เป็นโปรโตคอลโทรคมนาคมที่ใช้ในการสื่อสารทางวิทยุที่รับประกันการเปลี่ยนบิตในช่วงเวลาปกติเพื่อให้ผู้รับสามารถกู้คืนอัตรานาฬิกาจากข้อมูลได้ มันเพิ่มบิตเรตเป็นสองเท่า แต่ราคาถูกและใช้งานง่าย มันถูกใช้อย่างกว้างขวางโดยผู้ประกอบการวิทยุสมัครเล่น

แนวคิดนี้ง่ายมาก: ในระดับฮาร์ดแวร์นาฬิกาและสายข้อมูลเป็นเพียง XORed ด้วยกัน ในซอฟต์แวร์นี่คือภาพที่แปลงอินพุตสตรีมของบิตให้เป็นเอาต์พุตสตรีมอัตราสองเท่าโดยแต่ละอินพุต '1' ถูกแปลเป็น '01' และแต่ละอินพุต '0' แปลเป็น '10'

นี่เป็นปัญหาที่ง่าย แต่เปิดให้มีการใช้งานมากมายเนื่องจากลักษณะของบิตสตรีม นั่นคือการเข้ารหัสเป็นแนวคิดแบบกระบวนการทีละบิตแทนที่จะเป็นกระบวนการไบต์ต่อไบต์ ดังนั้นเราทุกคนเห็นด้วยกับ endianness บิตที่สำคัญน้อยที่สุดของอินพุตกลายเป็นไบต์ที่สำคัญที่สุดของเอาต์พุต

เวลาเล่นกอล์ฟ! เขียนฟังก์ชั่นที่กำหนดอาร์เรย์ความยาวตามอำเภอใจเป็นไบต์ส่งกลับอาร์เรย์ของข้อมูลแมนเชสเตอร์ที่เข้ารหัส

อินพุตและเอาต์พุตควรถูกพิจารณาเป็น little-endian ไบต์ที่มีนัยสำคัญน้อยที่สุดก่อนและ 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
  • ประสิทธิภาพจะต้องไม่น่ากลัวเกินไป: <10 วินาทีสำหรับ 16KB
  • ไบต์ที่สำคัญน้อยที่สุดก่อนในหน่วยความจำ

ความท้าทายด้านช่องทาง :

  • ท้าทายคำตอบของผู้ใช้คนอื่นโดยการพิสูจน์รหัสของคุณเร็วขึ้นหน่วยความจำมีประสิทธิภาพมากขึ้นหรือสร้างไบนารีที่เล็กลง

รับการเล่นกอล์ฟ! รหัสที่สั้นที่สุดชนะ!


2
"หน่วยความจำสำหรับเอาต์พุตต้องถูกจัดสรรตามรูทีนของคุณซึ่งไม่ได้จัดเตรียมไว้" ดูเหมือนจะเป็นข้อกำหนดที่ค่อนข้างแปลกเนื่องจากหลายภาษามีการจัดสรรหน่วยความจำอัตโนมัติอย่างสมบูรณ์
aaaaaaaaaaaa

มีอะไรในโลกที่ครอบครองคุณให้ใช้คำสั่งบิตที่แปลกประหลาด?
Peter Taylor

ลำดับบิตเหมาะสมเมื่อคุณพิจารณาสื่อทางกายภาพที่ใช้สำหรับ อัลกอริทึมนี้ใช้สำหรับการไหลของบิตแต่ละบิตที่เดินทางผ่านอากาศ ความจริงที่ว่าเราต้องเก็บไว้ในหน่วยความจำและเราเขียน hex msb-> lsb ทำให้ยุ่งยากเล็กน้อยในการติดตาม
mrmekon

คำตอบ:


6

GolfScript 28 ตัวอักษร

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

รุ่นที่เทียบเท่าโดยไม่มีการเพิ่มประสิทธิภาพที่ทำให้งงงวย:

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

รหัสรับเข้าเป็นอาร์เรย์ของจำนวนเต็มและกลับมาเหมือนกัน

สำหรับแต่ละหมายเลขในอาเรย์ตัวเลขจะถูกแปลงเป็นรูปแบบอาเรย์ฐานที่ 2 จากนั้นจะถูกแปลงกลับเป็นตัวเลขราวกับว่ามันเป็นฐาน 4 นี่มีผลกระทบของการเว้นระยะบิตที่มี 0 ในระหว่างแต่ละ 43691 จะถูกลบออกจากตัวเลขแล้วผลลัพธ์ก็คือไบนารีกลับด้านซึ่งเทียบเท่ากับการลบจำนวนจาก 43690 (43690 = 0b1010101010101010) จากนั้นตัวเลขจะถูกแบ่งออกเป็นสองส่วนโดยแปลงเป็นอาเรย์ 256 ฐานซึ่งอาเรย์จะถูกย่อยและลำดับของตัวเลขผลลัพธ์ทั้งสองจะกลับด้าน

อินพุตตัวอย่าง:

[1 2 3 241 242 243]

ตัวอย่างผลลัพธ์:

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

มันสั้นมากและฉลาดมาก! แม้ว่าดูเหมือนจะไม่ตรงกับ 16KB ในข้อเสนอแนะด้านประสิทธิภาพ <10s แต่อย่างน้อยสำหรับฉัน คุณใช้เวลา 43s บน Mac dual-core ของฉันเพื่อแปลงอาร์เรย์ของ 16384 1 ในการเปรียบเทียบการใช้งานไพ ธ อนขนาดใหญ่ของฉัน (2,419 ถ่าน) ใช้เวลา 0.06 วินาทีสำหรับ 16KB
mrmekon

ใช้เวลาน้อยกว่า 5 วินาทีในเครื่องของฉัน (Win 7) และส่วนใหญ่ที่แปลงอาเรย์เป็นเอาท์พุทข้อความซึ่งเท่าที่ฉันอ่านคำถามของคุณไม่ได้เป็นส่วนหนึ่งของความต้องการ แต่ GolfScript จะทำสิ่งใดโดยอัตโนมัติ บนสแต็กหลังจากการดำเนินการ หนึ่งสามารถทำให้รหัสวางผลลัพธ์แทนที่จะพิมพ์ (เพิ่ม; ถึงจุดสิ้นสุดของรหัส) หากคุณต้องการที่จะเห็นผลลัพธ์ (แม้ว่าจะไม่ใช่ส่วนหนึ่งของสเป็คคำถาม) ฉันรู้สองเทคนิคในการเร่งความเร็วเปลี่ยนเส้นทางไปยังไฟล์และพิมพ์อย่างชัดเจนในกลุ่มเล็ก ๆ โดยใช้คำสั่งพิมพ์:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

ใน Ubuntu vm (บน windows) ฉันได้รับ 8s สำหรับ 16kb สำหรับ mac ที่มีซีพียูที่ดีกว่าจะใช้เวลา 1m18 ฉันเดาทับทิมกว่าเรือที่มี OSX ช้ามากชะมัด
gnibbler

ดูเหมือนว่าการพิมพ์ทับทิมจะทำให้เครื่องของฉันช้าลงอย่างน่ารังเกียจ เฉพาะ 2 วินาทีเมื่อปิดการพิมพ์และ Ruby 1.9 (และ 5s ที่มี OSX ดั้งเดิม) มันดีกว่ามาก!
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;}

ส่วนการทำงานของรหัสคือวนรอบบิตของอักขระแต่ละตัวโดยสังเกตว่า (บิต (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)ใช้ ... กับแต่ละอินพุต "ไบต์" เป็น y ทำให้ได้สองไบต์ (จำนวนเต็ม) แต่ละรายการ ,ผลที่ได้คือแบนโดย
  • y#:~8#2เทียบเท่ากับ2 2 2 2 2 2 2 2 #: yหรือเวกเตอร์ของเลขฐานสองที่มีนัยสำคัญน้อยที่สุด 8 ตัวของ y
  • 4|. สลับด้านหน้าและด้านหลัง 4 บิตโดยหมุนได้ 4 ตำแหน่ง
  • (,.~-.)เทียบเท่ากับ3 :'(-. y) ,. y'หรือไม่ของการโต้แย้ง 'เย็บ' เพื่อโต้แย้ง (รับในรูปร่าง 8 2)
  • #.2 8$, แผ่ผลการให้บิตสตรีมปรับรูปร่างเป็น 2 แถว 8 และแปลงจากฐาน 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 อยู่ภายใต้. 25s, Intel Core Duo 1.83Ghz หรือคล้ายกัน


3

Haskell, 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

ประสิทธิภาพอยู่ในเกณฑ์ดี ที่ 1MB ใน ~ 1.2s บนแล็ปท็อปรุ่นเก่าของฉัน 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 + แบตเตอรี่, 138 117 ตัวอักษร

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

Python 87 ตัวอักษร

Mเป็นฟังก์ชั่นที่ร้องขอในปัญหา มันเรียกNแต่ละ nybble และ splices ทุกอย่างกลับเข้าไปในรายการ

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 ไบต์

ใช้ในชุดของไบต์ไบต์ที่สิบหกและแปลงเป็นกระแสข้อมูลไบนารีแมนเชสเตอร์

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

มันเข้ารหัสข้อมูล 16 KiB ใน 0.015 วินาทีและ 1 MiB ของข้อมูลในเวลาประมาณ 0.9 วินาที

รหัส ungolfed การใช้งานอื่น (อีกต่อไปและช้าลงประมาณสองเท่า) และกรณีทดสอบสามารถพบได้ในหน้าโปรแกรมแก้ไขโค้ดกอล์ฟของฉันใน Github

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.