Manchester mengkodekan aliran data

14

Pengkodean Manchester adalah protokol telekomunikasi yang digunakan dalam komunikasi radio yang menjamin transisi bit secara berkala sehingga penerima dapat memulihkan laju jam dari data itu sendiri. Ini menggandakan bitrate, tetapi murah dan mudah diimplementasikan. Ini banyak digunakan oleh operator radio amatir.

Konsepnya sangat sederhana: pada tingkat perangkat keras, jam dan jalur data secara sederhana disatukan. Dalam perangkat lunak, ini digambarkan sebagai mengubah aliran input bit ke aliran output laju ganda, dengan setiap input '1' diterjemahkan ke '01' dan setiap input '0' diterjemahkan ke '10'.

Ini adalah masalah yang mudah, tetapi terbuka untuk banyak implementasi karena sifat bitstreamnya. Artinya, pengkodean secara konseptual adalah proses bit-by-bit, bukan proses byte-by-byte. Jadi kita semua sepakat pada endianness, bit input paling tidak signifikan menjadi byte paling signifikan dari output.

Waktu bermain golf! Tulis fungsi yang, diberikan array panjang byte yang sewenang-wenang, mengembalikan array dari manchester data yang disandikan.

Input dan output harus dianggap little-endian, byte paling signifikan pertama, dan BIT paling signifikan pertama dalam bit stream.

Gambar bitstream 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

Contoh :

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]

Aturan :

  • Solusi hanya membutuhkan algoritma untuk mengkonversi input ke output.
  • Mendapatkan input dan output cetak BUKAN merupakan bagian yang diperlukan dari solusi, tetapi dapat dimasukkan Anda disarankan untuk memberikan kode uji / cetak Anda jika tidak termasuk dalam solusi Anda.
  • Input adalah larik byte 8-bit (apa pun artinya dalam bahasa pilihan Anda), BUKAN string teks. Anda dapat menggunakan string sebagai format penyimpanan jika sesuai dengan bahasa Anda, tetapi karakter yang tidak dapat dicetak (mis. 0xFF) harus didukung. Input juga bisa memakan waktu lama jika perlu.
  • Memori untuk keluaran harus dialokasikan oleh rutinitas Anda, bukan disediakan. sunting: persyaratan yang tidak perlu
  • Output juga merupakan array byte 8-bit, dan panjang jika perlu.
  • Harus mendukung setidaknya 16KB input
  • Kinerja tidak boleh terlalu mengerikan: <10s untuk 16KB
  • Byte terkecil-signifikan pertama dalam memori.

Tantangan saluran samping :

  • Tantang jawaban pengguna lain dengan membuktikan kode Anda lebih cepat, lebih hemat memori, atau menghasilkan biner yang lebih kecil!

Dapatkan golf! Kode terpendek menang!

mrmekon
sumber
2
"Memori untuk keluaran harus dialokasikan oleh rutinitas Anda, bukan disediakan." Itu sepertinya persyaratan yang cukup aneh karena banyak bahasa memiliki alokasi memori yang sepenuhnya otomatis.
aaaaaaaaaaaa
Apa yang membuatmu menggunakan perintah bit yang aneh?
Peter Taylor
Urutan bit masuk akal ketika Anda mempertimbangkan media fisik ini digunakan untuk; Algoritma ini untuk aliran bit individual yang bepergian di udara. Fakta bahwa kita harus menyimpannya dalam memori, dan kita menulis hex msb-> lsb, membuatnya sedikit sulit untuk dilacak.
mrmekon

Jawaban:

6

GolfScript 28 karakter

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

Versi yang setara tanpa optimasi yang membingungkan:

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

Kode menerima input sebagai array bilangan bulat, dan kembali ditto.

Untuk setiap angka dalam array angka dikonversi ke bentuk array basis 2, kemudian dikonversi kembali ke angka seolah-olah itu basis 4, ini memiliki efek jarak bit dengan 0 di antara masing-masing. 43691 kemudian dikurangi dari angka, dan hasilnya adalah biner terbalik, ini setara dengan mengurangi angka dari 43690 (43690 = 0b101010101010101010). Angka tersebut kemudian dibagi menjadi dua bagian dengan mengubahnya menjadi array 256 basis, array didekomposisi dan urutan dua angka yang dihasilkan dibalik.

Input contoh:

[1 2 3 241 242 243]

Contoh output:

[169 170 166 170 165 170 169 85 166 85 165 85]
aaaaaaaaaaaa
sumber
Itu sangat pendek, dan sangat pintar! Meskipun sepertinya tidak memenuhi 16KB dalam saran kinerja <10s, setidaknya bagi saya; Anda membutuhkan 43 detik pada Mac dual-core saya untuk mengonversi array 16384 1. Sebagai perbandingan, implementasi python saya yang sangat besar (2419 char) membutuhkan waktu 0,06 detik untuk 16KB.
mrmekon
Butuh waktu kurang dari 5 detik pada mesin saya (Win 7), dan sebagian besar dari itu mengubah array menjadi output teks, yang sejauh yang saya baca pertanyaan Anda bukan bagian dari persyaratan, tetapi GolfScript melakukannya secara otomatis dengan yang tersisa di tumpukan setelah eksekusi. Seseorang dapat dengan mudah membuat kode menjatuhkan hasil daripada mencetaknya (tambahkan; pada akhir kode). Jika Anda ingin melihat output (meskipun itu bukan bagian dari spesifikasi pertanyaan.) Saya tahu dua trik untuk mempercepatnya, mengarahkannya ke file, dan mencetaknya secara eksplisit dalam potongan kecil menggunakan perintah cetak:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa
Dalam vm ubuntu (di windows), saya mendapatkan 8s untuk 16kb. Pada mac dengan cpu yang lebih baik butuh 1m18. Saya kira batu delima daripada kapal dengan OSX hanya sangat lambat
gnibbler
Sepertinya pencetakan ruby ​​menjijikkan pada mesin saya. Hanya 2s dengan pencetakan dimatikan dan Ruby 1.9 (dan 5s dengan versi OSX asli). Itu lebih baik!
mrmekon
3

c - 224 karakter

Saya percaya bahwa ini fungsional, termasuk alokasi kebutuhan memori sejak dijatuhkan.

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

Bagian yang berfungsi dari kode adalah loop atas bit masing-masing karakter, mencatat bahwa ((bit + 1) eksklusif-atau 3) adalah pasangan bit output, dan menerapkan banyak logika shifting dan masking untuk membuat semuanya berbaris.

Seperti halnya c, ia bekerja pada data sebagai karakter. Scaffold tes tidak akan menerima 0 byte (karena c memperlakukannya sebagai string mengakhiri), tetapi kode kerja tidak memiliki batasan seperti itu.

Mungkin golf sedikit lebih banyak dengan menyalin pekerjaan konversi byte inline.

Uji coba (dengan perancah uji yang ditingkatkan):

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

Berkomentar, lebih sedikit ketergantungan mesin, dan dengan scaffold uji

/* 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;
}
dmckee --- mantan kucing moderator
sumber
3

J, 36

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

Garis besar penjelasan (Lihat J Kosakata untuk referensi):

  • ,@:(3 :'...'"0)menerapkan ... untuk setiap input "byte" sebagai y, menghasilkan masing-masing dua byte (integer). Hasilnya diratakan oleh, .
  • y#:~8#2setara dengan 2 2 2 2 2 2 2 2 #: y, atau vektor dari 8 basis-2 digit paling signifikan dari y.
  • 4|. menukar depan dan belakang 4 bit dengan memutar 4 posisi.
  • (,.~-.) setara dengan 3 :'(-. y) ,. y' , atau tidak dari argumen 'dijahit' ke argumen (mengambil bentuk 8 2).
  • #.2 8$, ratakan hasilnya dengan memberikan bitstream, membentuk kembali menjadi 2 baris 8, dan mengkonversi dari basis 2.

Contoh penggunaan (J, interaktif):

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

Informasi kecepatan (J, interaktif):

   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

Berarti waktu untuk 16kb hanya di bawah 0,25s, Intel Core Duo 1,83Ghz atau serupa.

Jesse Millikan
sumber
3

Haskell, 76 karakter

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

Tes berjalan:

> 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

Performa baik dalam spesifikasi. pada 1MB di ~ 1.2s pada laptop lawas saya. Itu menderita karena input dikonversi ke dan dari daftar, daripada diproses sebagai 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

Sumbernya, 2040-Manchester.hs , termasuk kode, tes, dan fungsi utama untuk filter baris perintah.

MtnViewMark
sumber
3

OCaml + Baterai, 138 117 karakter

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

Tes:

Dengan

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

Hasilnya adalah:

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"

Sebagai patokan, dengan:

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

Saya mendapat:

# benchmark 16_384;;
- : float = 0.115520954132080078

di MacBook saya.

Matías Giovannini
sumber
1

Python, 87 karakter

Madalah fungsi yang diminta dalam masalah. Ini panggilan Nuntuk setiap nybble dan menyambungkan semuanya kembali ke daftar.

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

menghasilkan

['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']
Keith Randall
sumber
1

APL (Dyalog Extended) , 22 byte

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

Cobalah online!

Port jawaban 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.
lirtosiast
sumber
0

C, 164 byte

Dibawa dalam serangkaian byte hex dan dikonversi ke aliran biner 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");}}

Uji:

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

Keluaran:

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

Generator data uji 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 uji waktu inti:

time ./a.out `./test_data` > test.out 
real    0m0.096s
user    0m0.090s
sys 0m0.011s
Zeeee
sumber
Posting pertama yang bagus, tetapi kami biasanya tidak mencoba mengaburkan kode kami. Lebih pendek ya, lebih sulit untuk membaca tidak.
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;}

Diberikan input [0, 1, 2, 3, 4, 5], ia mengembalikan:

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

Ini mengkodekan 16 KiB data dalam 0,015 detik dan 1 MiB data dalam waktu sekitar 0,9 detik.

Kode ungolfed, implementasi lain (lebih lama dan sekitar dua kali lebih lambat) dan kasus uji dapat ditemukan di halaman solusi kode-golf saya di Github.

aksioma
sumber