マンチェスターはデータストリームをエンコードします


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ビットバイトの配列であり、必要に応じて長さです。
  • 少なくとも16KBの入力をサポートする必要があります
  • パフォーマンスがひどすぎてはいけません:16KBで<10秒
  • メモリ内の最下位バイトが最初。

サイドチャネルの課題

  • コードの高速化、メモリ効率の向上、または小さなバイナリの生成を証明して、他のユーザーの答えに挑戦しましょう!

ゴルフをしてください!最短のコードが勝ちます!


2
「出力用のメモリは、ルーチンではなく、提供される必要があります。」多くの言語には完全に自動のメモリ割り当てがあるため、これは非常に奇妙な要件のようです。
aaaaaaaaaaaa

このような奇妙なビット順序を使用するために、地球上で何を所有しましたか?
ピーターテイラー

ビットの順序は、これが使用される物理媒体を検討する際に意味があります。このアルゴリズムは、空中を移動する個々のビットのストリーム用です。メモリに保存する必要があり、16進数のmsb-> lsbを記述する必要があるため、追跡するのが少し難しくなります。
-mrmekon

回答:


6

GolfScript 28文字

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

最適化を難読化しない同等のバージョン:

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

このコードは、整数の配列として入力を受け入れ、同じように返します。

配列内の各数値について、数値は基数2の配列形式に変換され、その後、基数4であるかのように数値に変換されます。次に、数値から43691が減算され、結果が2進反転されます。これは、43690から数値を減算することと同等です(43690 = 0b1010101010101010)。次に、数値をベースの256配列に変換して2つの部分に分割し、配列を分解して、結果の2つの数値の順序を逆にします。

入力例:

[1 2 3 241 242 243]

出力例:

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

それは途方もなく短く、非常に賢いです!少なくとも私にとっては、10秒未満のパフォーマンスの提案では16KBに満たないようです。私のデュアルコアMacでは、16384個の1の配列を変換するために43秒かかります。それに比べて、私の大規模(2419文字)のPython実装は16KBで0.06秒かかります。
mrmekon

私のマシン(Win 7)では5秒もかからず、そのほとんどは配列をテキスト出力に変換します。質問を読む限り、これは要件の一部ではありませんが、GolfScriptは自動的に残りを何でも処理します。実行後のスタック上。結果を印刷するのではなく、単にコードにドロップさせることができます(コードの最後に;を追加します)。(。それが問題の仕様の一部ではないですが)あなたが出力を見たい場合は、私はそれをスピードアップするための2つのトリックを知って、それをファイルにリダイレクトし、印刷コマンドを使用して小さな塊に明示的にそれを印刷:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

ubuntu vm(windows)では、16kbで8秒になります。より良いCPUを搭載したMacでは、1m18かかりました。OSXを搭載した船よりもルビーはひどく遅いと
思い

私のマシンではルビーの印刷がうんざりするほど遅いようです。印刷をオフにしてRuby 1.9(およびネイティブOSXバージョンで5秒)をオフにしたのは2秒のみです。それははるかに良いです!
-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;}

コードの作業部分は、各文字のビットのループです。((bit + 1)exclusive-or 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として適用し、それぞれ2バイト(整数)になります。結果はによって平坦化され,ます。
  • y#:~8#22 2 2 2 2 2 2 2 #: y、またはyの8最下位2桁のベクトルと同等です。
  • 4|. 4ポジションずつ回転することにより、フロントとバックの4ビットを交換します。
  • (,.~-.)3 :'(-. y) ,. y'、引数に「ステッチ」された引数と同等であるか、そうではありません(形状8 2を取ります)。
  • #.2 8$, 結果をフラット化し、ビットストリームを生成し、8行2列に整形し、ベース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

パフォーマンスは仕様の範囲内です。私の古いラップトップでは1.2秒以内に1MBでした。入力がリストとして変換され、リストから変換されるため、として処理されるため、問題が生じ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各ニブルを呼び出し、すべてをリストにつなぎ直します。

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バイト

一連の16進バイトを受け取り、マンチェスターバイナリストリームに変換します。

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

0.015秒で16 KiBのデータをエンコードし、約0.9秒で1 MiBのデータをエンコードします。

使用されていないコード、別の実装(より長く、約2倍遅い)、およびテストケースは、Githubのコードゴルフソリューションページにあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.