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


14

Манчестерское кодирование - это телекоммуникационный протокол, используемый в радиосвязи, который гарантирует битовые переходы с регулярным интервалом, чтобы приемник мог восстановить тактовую частоту из самих данных. Он удваивает битрейт, но дешев и прост в реализации. Широко используется радиолюбителями.

Концепция очень проста: на аппаратном уровне часы и линии данных просто объединяются в XOR. В программном обеспечении это изображается как преобразование входного потока битов в выходной поток с двойной скоростью, причем каждый вход «1» транслируется в «01», а каждый вход «0» транслируется в «10».

Это простая проблема, но она открыта для многих реализаций из-за своей природы потока битов. То есть кодирование концептуально является побитовым процессом, а не побитовым процессом. Таким образом, мы все согласны с порядком байтов, младшие значащие биты входных данных становятся наименее значимыми байтами выходных данных.

Время игры в гольф! Напишите функцию, которая, учитывая массив байтов произвольной длины, возвращает массив этих манчестерских данных.

Ввод и вывод должны рассматриваться как младшие байты, младший значащий байт первым и младший значащий бит в битовом потоке.

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 КБ ввода
  • Производительность не должна быть слишком ужасной: <10 с для 16 КБ
  • Наименее значимый байт первым в памяти.

Задача побочного канала :

  • Испытайте ответ другого пользователя, доказав, что ваш код быстрее, эффективнее использует память или создает меньший двоичный файл!

Получить гольф! Самый короткий код выигрывает!


2
«Память для вывода должна быть выделена вашей программой, а не предоставлена». Это кажется довольно странным требованием, поскольку многие языки имеют полностью автоматическое распределение памяти.
aaaaaaaaaaaa

Что, черт возьми, побудило тебя использовать такой странный битовый порядок?
Питер Тейлор

Порядок битов имеет смысл, когда вы рассматриваете физическую среду, для которой он используется; Этот алгоритм предназначен для потока отдельных битов, путешествующих по воздуху. Тот факт, что мы должны хранить его в памяти, и что мы пишем 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]

Это смехотворно коротко и очень умно! Хотя кажется, что он не соответствует 16 КБ в <10-кратном предложении производительности, по крайней мере для меня; на моем двухъядерном Mac требуется 43 секунды, чтобы преобразовать массив из 16384 единиц. Для сравнения, моя массивная (на 2419 символов) реализация Python занимает 0,06 с для 16 КБ.
mrmekon

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

В Ubuntu VM (на Windows), я получаю 8 с за 16 КБ. На Mac с лучшим процессором это заняло 1m18. Я думаю, что рубин, который поставляется с OSX, просто ужасно медленный
gnibbler

Похоже, что печать на рубине отвратительно медленна на моей машине. Только 2 с выключенной печатью и Ruby 1.9 (и 5 с с родной версией OSX). Это гораздо лучше!
mrmekon

3

с - 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 у.
  • 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 КБ чуть меньше 0,25 с, Intel Core Duo 1,83 ГГц или аналогичный.


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

Питон, 87 символов

Mявляется функцией, запрошенной в проблеме. Он вызывает Nкаждый кусок и объединяет все обратно в список.

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 КиБ данных за 0,015 секунды и 1 МиБ данных за 0,9 секунды.

Код ungolfed, другая реализация (длиннее и примерно в два раза медленнее) и контрольные примеры можно найти на моей странице решений для code-golf на Github.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.