Manchester bir veri akışını kodlar


14

Manchester kodlaması , radyo iletişiminde kullanılan ve bir alıcının saat hızını verilerin kendisinden kurtarabilmesi için düzenli aralıklarla bit geçişlerini garanti eden bir telekom protokolüdür. Bit hızını iki katına çıkarır, ancak uygulanması ucuz ve kolaydır. Amatör radyo operatörleri tarafından yaygın olarak kullanılmaktadır.

Kavram çok basit: donanım düzeyinde, saat ve veri hatları birlikte XORed. Yazılımda, bu, bir bit giriş akışını çift oranlı bir çıkış akışına dönüştürmek olarak tasvir edilir, her bir '1' girişi bir '01'e çevrilir ve her bir' 0 'girişi bir' 10'a çevrilir.

Bu kolay bir sorundur, ancak bit akımı doğası nedeniyle birçok uygulamaya açıktır. Yani, kodlama byte byte byte işlemi yerine kavramsal olarak bit-by-bit bir süreçtir. Bu yüzden hepimiz endianiteye katılıyoruz, girdinin en az önemli bitleri çıktının en az önemli baytı haline geliyor.

Golf zamanı! Rasgele uzunluktaki bayt dizisi verildiğinde, bu veri manchester'ının kodlanmış bir dizisini döndüren bir işlev yazın.

Girdi ve çıktı, bit akışında küçük endian, önce en az önemli bayt ve önce en az anlamlı BIT olarak düşünülmelidir.

ASCII bit akımı çizimi :

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

Örnekler :

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]

Kurallar :

  • Çözüm yalnızca girdiyi çıktıya dönüştürmek için algoritma gerektirir.
  • Giriş ve baskı çıktısının alınması, çözümün gerekli bir parçası DEĞİLDİR, ancak dahil edilebilir. Çözümünüze dahil edilmemişse, test / yazdırma kodunuzu girmeniz önerilir.
  • Girdi, bir metin dizesi DEĞİL, 8 bit baytlık bir dizidir (dilinizde ne anlama gelirse gelsin). Dizeleri dilinize uygunsa depolama biçimi olarak kullanabilirsiniz, ancak yazdırılamayan karakterler (yani 0xFF) desteklenmelidir. Gerekirse giriş de uzun sürebilir.
  • Çıktı için bellek, sağlanmayan rutininiz tarafından ayrılmalıdır. düzenleme: gereksiz gereksinim
  • Çıktı ayrıca 8 bit baytlık bir dizidir ve gerekirse bir uzunluktur.
  • En az 16KB girişi desteklemelidir
  • Performans çok korkunç olmamalı: 16KB için <10s
  • Hafızada ilk olarak en az önemli bayt.

Yan kanal zorluğu :

  • Kodunuzun daha hızlı, bellekte daha verimli olduğunu veya daha küçük bir ikili veri ürettiğini kanıtlayarak başka bir kullanıcının yanıtına meydan okuyun!

Golf yapın! En kısa kod kazanır!


2
"Çıktı için bellek, rutininiz tarafından verilmelidir, sağlanmamıştır." Birçok dil tamamen otomatik bellek tahsisine sahip olduğundan bu oldukça garip bir gereklilik gibi görünüyor.
aaaaaaaaaaaa

Yeryüzünde ne kadar tuhaf bir bit düzeni kullanıyorsunuz?
Peter Taylor

Bunun için kullanılan fiziksel ortamı düşündüğünüzde bit sırası mantıklıdır; bu algoritma havadan geçen ayrı bitlerin akışı içindir. Hafızada saklamamız ve onaltılık msb-> lsb yazmamız gerektiğinin takip edilmesi biraz zorlaşır.
mrmekon

Yanıtlar:


6

GolfScript 28 karakter

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

Optimize edici optimizasyon olmadan eşdeğer versiyon:

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

Kod, girdiyi bir tamsayı dizisi olarak kabul eder ve ditto değerini döndürür.

Dizideki her sayı için sayı, temel 2 dizi formuna dönüştürülür, daha sonra temel 4'teki gibi bir sayıya geri dönüştürülür, bu, bitlerin her biri arasında 0 ile boşluk bırakma etkisine sahiptir. 43691 daha sonra sayıdan çıkarılır ve sonuç ikili olarak tersine çevrilir, bu sayı 43690'dan (43690 = 0b1010101010101010) çıkarılmaya eşdeğerdir. Daha sonra sayı, bir taban 256 dizisine dönüştürülerek iki parçaya bölünür, dizi ayrıştırılır ve elde edilen iki sayının sırası ters çevrilir.

Örnek girdi:

[1 2 3 241 242 243]

Örnek çıktı:

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

Bu gülünç derecede kısa ve çok akıllı! En azından benim için 16KB'nin <10s performans önerisinde olduğu görülmese de; seninki 16384 1 bir dizi dönüştürmek için benim çift çekirdekli Mac 43s alır. Buna karşılık, büyük (2419 karakter) python uygulamam 16KB için 0.06s alır.
mrmekon

Makinemde 5 saniyeden daha az sürüyor (Win 7) ve çoğu diziyi metin çıktısına dönüştürüyor, bu da soruyu okuduğum kadarıyla gereksinimin bir parçası değil, ancak GolfScript bunu otomatik olarak kalan herhangi bir şeyle yapıyor sonra yürütme yığını. Kodun yazdırmak yerine sonucu düşürmesi yeterlidir (kodun sonuna ekleyin; ekleyin). Çıktıyı görmek istiyorsanız (bu soru özelliklerinin bir parçası değildir.) Hızlandırmak için iki püf noktası biliyorum, bir dosyaya yönlendirin ve baskı komutlarını kullanarak küçük parçalar halinde açıkça yazdırın:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

Bir ubuntu vm'de (pencerelerde), 16kb için 8s alıyorum. Daha iyi bir cpu ile bir mac üzerinde 1m18 aldı. Ben OSX ile gemiler daha yakut sanırım sadece çok yavaş
gnibbler

Makinemde yakut baskının aşırı yavaş olduğu anlaşılıyor. Baskı kapalıyken yalnızca 2s ve Ruby 1.9 (ve yerel OSX sürümüyle 5s). Çok daha iyi!
mrmekon

3

c - 224 karakter

Düştüğünden beri bellek gereksiniminin tahsisi de dahil olmak üzere bunun işlevsel olduğuna inanıyorum.

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

Kodun çalışma kısmı, her karakterin bitleri üzerinde bir döngü olup, ((bit + 1) exclusive-veya 3) çıkış bit çifti olduğunu ve her şeyi sıralamak için çok sayıda kaydırma ve maskeleme mantığı uygular.

C'nin alışkanlığı gibi, veriler üzerinde karakter olarak çalışır. Sınama iskelesi 0 bayt kabul etmez (çünkü c bunları dize bitişi olarak kabul eder), ancak çalışma kodunun böyle bir sınırlaması yoktur.

Bayt dönüştürme işini yerinde kopyalayarak biraz daha golf oynayabilir.

Test çalıştırması (geliştirilmiş test iskele ile):

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

Yorum yapılmış, makineye daha az bağımlı ve test iskelesi ile

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

Açıklamanın ana hatları ( Referans için bkz. J Kelime Bilgisi ):

  • ,@:(3 :'...'"0)... her bir "bayt" girişini y olarak uygular ve her biri iki bayt (tamsayı) ile sonuçlanır. Sonuç tarafından düzleştirilir ,.
  • y#:~8#22 2 2 2 2 2 2 2 #: y"Y", y'nin en az önemli 8 baz-2 basamağına eşdeğer veya vektörüdür.
  • 4|. 4 konumu döndürerek ön ve arka 4 biti değiştirir.
  • (,.~-.)3 :'(-. y) ,. y'argümana 'dikişli' argümanına eşdeğerdir veya değildir (şekil 8 2'yi alır).
  • #.2 8$, bit akışını veren sonucu düzleştirir, 8'lik 2 satıra yeniden şekillendirir ve taban 2'den dönüştürür.

Örnek kullanım (J, etkileşimli):

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

Hız bilgisi (J, etkileşimli):

   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 için ortalama süre .25s'nin altında, Intel Core Duo 1.83Ghz veya benzeri.


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)

Test çalıştırmaları:

> 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

Performans spesifikasyonlar dahilindedir. benim eski dizüstü bilgisayarda ~ 1.2s 1MB. Giriş, bir listeye ve listeden dönüştürüldüğünden, daha sonra a olarak işlendiğinden acı çeker 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 kaynağı, komut satırı filtresi için kodu, testleri ve ana işlevi içerir.


3

OCaml + Piller, 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]?]))

Testler:

İle

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

Sonuçlar:

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"

Karşılaştırma ölçütü olarak:

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

Alırım:

# benchmark 16_384;;
- : float = 0.115520954132080078

MacBook'umda.


1

Python, 87 karakter

Msorunda istenen işlevdir. NHer nybble'ı çağırır ve her şeyi bir listeye ekler.

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

üretir

['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 (Genişletilmiş Dyalog) , 22 bayt

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

Çevrimiçi deneyin!

GolfScript yanıtının bağlantı noktası.

∊(⌽(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 bayt

Bir dizi onaltılık bayt alır ve manchester ikili akışına dönüştürür.

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

Ölçek:

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

Çıktı:

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 veri seti jeneratörü:

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 çekirdek zaman deneme:

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

Güzel bir ilk gönderi, ama genellikle kodumuzu gizlemeye çalışmayız. Daha kısa evet, okuması daha zor hayır.
Rɪᴋᴇʀ

0

PHP, 156 bayt

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

Girdi göz önüne alındığında, [0, 1, 2, 3, 4, 5]döndürür:

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

0.015 saniyede 16 KiB veri ve yaklaşık 0.9 saniyede 1 MiB veri kodlar.

Çözülmemiş kod, başka bir uygulama (daha uzun ve yaklaşık iki kez daha yavaş) ve test senaryoları Github'daki kod golf çözümleri sayfamda bulunabilir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.