Манчестер кодує потік даних


14

Кодування в Манчестері - це телекомунікаційний протокол, який використовується в радіозв'язку, який гарантує перехід бітів через регулярний інтервал, щоб приймач міг відновлювати тактову частоту з самих даних. Він подвоює бітрейт, але дешевий і простий у виконанні. Він широко використовується радіооператорами-любителями.

Концепція дуже проста: на апаратному рівні лінії та годинник та дані просто XORed разом. У програмному забезпеченні це зображено як перетворення вхідного потоку бітів у вихідний потік з двома швидкістю, при цьому кожен вхід '1' переводиться на '01', а кожен вхід '0' перекладається на '10'.

Це проста проблема, але відкрита для багатьох реалізацій через її біткоїнний характер. Тобто кодування є концептуально процесом біт-біт замість процесу байт-байт. Таким чином, ми всі погоджуємося на витривалість, найменш значущі біти вхідних даних стають найменш значущим байтом виводу.

Час гольфу! Напишіть функцію, яка, задаючи масив байтів довільної довжини, повертає масив цих даних, закодованих manchester.

Введення та виведення слід вважати малоеквієнтним, найменш значущим байтом першим і найменш значущим 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-бітових байтів і довжина, якщо це необхідно.
  • Повинна підтримувати принаймні 16 КБ
  • Продуктивність не повинна бути занадто жахливою: <10s за 16KB
  • Найменш значущий байт перший в пам'яті.

Виклик бічних каналів :

  • Киньте виклик відповіді іншого користувача, довівши свій код швидше, ефективніше пам’яті або створити менший двійковий файл!

Займіться гольфом! Найкоротший код виграє!


2
"Пам'ять для виведення повинна бути розподілена вашою процедурою, а не надана." Це здається досить дивною вимогою, оскільки багато мов мають повністю автоматичний розподіл пам'яті.
aaaaaaaaaaaa

Що на Землі володіло тобою, щоб скористатися таким химерним замовленням бітів?
Пітер Тейлор

Порядок бітів має сенс, якщо врахувати фізичне середовище, для якого воно використовується; цей алгоритм призначений для потоку окремих біт, що подорожують по повітрю. Той факт, що нам потрібно зберігати його в пам'яті, а також те, що ми пишемо шістнадцятковий msb-> lsb, робить це трохи складним для відстеження.
mrmekon

Відповіді:


6

28 символів GolfScript

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

Еквівалентна версія без обтяжливої ​​оптимізації:

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

Код приймає введення як масив цілих чисел і повертає ditto.

Для кожного числа в масиві число перетворюється у форму масиву бази 2, потім воно перетворюється назад в число, як якщо б воно було базовим 4, це призводить до того, що біти будуть розташовані між 0 між ними. 43691 потім віднімається від числа, а результат є двійковим перевернутим, це еквівалентно відніманню числа від 43690 (43690 = 0b101010101010101010). Потім число розбивається на дві частини, перетворюючи його в базовий масив 256, масив розкладається, а порядок двох отриманих чисел інвертується.

Приклад введення:

[1 2 3 241 242 243]

Приклад виводу:

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

Це смішно коротко і дуже розумно! Хоча це, здається, не відповідає 16 КБ за пропозицію щодо продуктивності <10s, принаймні для мене; ваш переймає 43-х на моєму двоядерному Mac для перетворення масиву 16384 1. Для порівняння, моя масивна (2419 char) реалізація пітона займає 0,06 секунди за 16 КБ.
mrmekon

На моїй машині це займає менше 5 секунд (Win 7), і більшість з них - це перетворення масиву на вихід тексту, який, наскільки я читав ваше запитання, не є частиною вимоги, але GolfScript робить це автоматично, якщо не залишилося нічого на стеку після виконання. Можна просто змусити код упустити результат, а не надрукувати його (додати; до кінця коду). Якщо ви хочете побачити вихід (хоча це не є частиною специфікацій запитання.) Я знаю два прийоми для його прискорення, перенаправляйте його у файл і друкуйте його явно невеликими шматками за допомогою команд друку:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaaa

У 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 найменш значущих базових-2 цифр 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

Середній час для 16 кбіт трохи нижче .25s, Intel Core Duo 1,83 ГГц або подібний.


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 Мб в ~ 1,2 секунди на моєму старовинному ноутбуці. Він страждає через те, що вхід перетворюється в і зі списку, а не обробляється як 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

Пітон, 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 байти

Займає серію шістнадцяткових байтів і перетворюється на бінарний потік манчестер.

#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

Генератор тестових наборів даних 16 кб:

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 секунди.

Невикористаний код, інша реалізація (довше і приблизно вдвічі повільніше) та тестові випадки можна знайти на моїй сторінці рішень з кодовим гольфом на Github.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.