可変長の数量をデコードする


16

可変長数値表現(とも称されるVLQまたはuintvar)必要なバイト数としてのみ使用して28ビット整数値まで符号化する方法です。これは、特定のイベントデータのサイズを最小化する方法として、MIDIファイル形式で使用されていました。

仕組みはかなり簡単です。ビッグエンディアンの一連のバイトとして、各バイトの最上位ビット(MSB)1は、別のVLQバイトが続くことを示すためのものです。各バイトの残りの7ビットは、デコードされた値を構成します。

例(ウィキペディアから):

[ 0x86, 0xc3, 0x17 ] => 106903

ここに画像の説明を入力してください その他の参照:ウィキペディアいくつかの男

チャレンジ:

可変長の数量を指定して、整数値に変換します。

入力:

整数の有効なVLQを表す1〜4バイトまたは32ビット値タイプのリスト。

出力:

VLQ入力の整数値。

ルールとスコアリング:

  • これはコードゴルフなので、各言語のバイト単位の最短回答が勝ちです。
  • 標準ルールデフォルトのI / Oルールが適用されます。
  • (もちろん)禁止されている抜け穴
  • コードのテスト(TIO.runなど)のリンクを提供してください。
  • 回答の明確な説明を強くお勧めします。
  • この変換を処理するビルトインは禁止されていませんが、それらを使用しないほうがはるかに興味深いです。

テストケース:

Input (VLQ)                   Output (int)

[                   0x00 ] => 0
[                   0x07 ] => 7
[                   0x7f ] => 127
[             0x81, 0x00 ] => 128
[             0xC0, 0x00 ] => 8192
[             0xff, 0x7f ] => 16383
[       0x81, 0x80, 0x00 ] => 16384
[       0x86, 0xc3, 0x17 ] => 106903
[       0xbd, 0x84, 0x40 ] => 1000000
[       0xff, 0xff, 0x7f ] => 2097151 
[ 0xC0, 0x80, 0x80, 0x00 ] => 134217728  
[ 0xFF, 0xFF, 0xFF, 0x7F ] => 268435455  

注:バイトを入力または出力として表すために16進リテラルを使用する必要はありません。プラットフォームに適している場合は[ 129, 128, 0 ]、10進リテラル()、整数(0x80818000)、またはその他の適切なバイト/オクテット表現を使用できます。1〜4バイト/オクテットを表す限り、フォーマットは柔軟です。

離れてゴルフ!


入力の最後のバイトは<128であることが保証されていますか?または、次のようなケースをサポートする必要があり[0x01, 0x80, 0x02] => 1ますか?
アーナルド

5
@Arnauld私は今あなたが何を得ているかをよく見ています。そして振り返ってみると、あなたが言及したケースは必要だったのは良かったでしょう。たとえば、MIDIでは、データのストリームを読み取るため、どのバイトが最後のバイトであるかを必ずしも知る必要はありません。リストの最後のバイトがVLQの最後のバイトであることを保証し、MSBを無関係にし、実際にはVLQの目的を無効にします。同様に、これらの(チャレンジに対して有効な)ルーチンを必ずしもMIDIファイルのデコードに使用できるとは限りません。完全に私が悪い!これをサンドボックスにもっと長く保存しておくべきだった...
640KB

5
これは、サンドボックスでのチャレンジを見たことがあり、十分な注意を払っていなかったと思うので、部分的には悪いことでもあります。しかし、はい、それは私が考えていたものです:バイトのリストを与えられ、いずれかの出力最初のVLQ値または出力の全てVLQ値
アーナルド

1
@KevinCruijssen、可変長の量はバイトストリームであると想定されています。技術的には、MSB = 0マーカーに到達することで終了するタイミングのみがわかります。ルールがそれを完全に把握していなかったのは知っていますが、VLQの定義により、ノーと言う必要があります。
640 KB

1
@gwaugh OK、それは理にかなっており、私は推論を理解することができます。MathGolfの回答を適宜修正します。:)
ケビンクルーッセン

回答:







3

05AB1E、6バイト

žy%žyβ

オンラインでお試しください!

12827


ええ、その組み込みは今日では役に立たない。レガシーバージョンでは、プログラムで数字の前に数字がある場合にのみ、いくつかの使用法を見ることができました。それ以外の場合は、単に使用できます7o。最近では、特定の3バイト整数(範囲[101,355])を2バイトで圧縮できるので、128でも問題はありませƵRん。または、プログラムで数字がその後ろにある場合は、4o/ 4n/ になります 数字は私が起こるとは思わない16、前である場合にのみ、組み込みに便利です。..
ケビンCruijssen



2

APL + WIN、22バイト

整数のベクトルのプロンプト:

2⊥¯32↑,0 1↓⍉(8⍴2)⊤¯4↑⎕

オンラインでお試しください!Dyalog Classic提供

説明:

¯4↑⎕ Pad the vector to 4 integers from the right.

⍉(8⍴2)⊤ Convert to a matrix of 8 bit values.

,0 1↓ drop the MSBs and flatten to a vector.

2⊥¯32↑ pad bit vector to 32 bits starting at LSB and convert back to integer.

2

スタックス、12 バイト

ü╫ôà¡k2Wù}a☺

staxlang.xyzで実行してデバッグしてください!

開梱(14バイト)および説明:

rk128%128i^#*+
r                 Reverse 'cuz big-endian
 k                Fold from the left using block:
  128%              Modulize by 128
      128i^#        Push 128 to the power of (one plus the iteration index)
            *       Multiply
             +      Add to the total
                  Implicit print

Staxにはベース変換が組み込まれていますが、文字列でのみ機能します。それはほとんどしかし、整数のリストに取り組んでいます。問題はStaxのの処理にあり0ます。

文字列は整数のリストです。このようなリストを文字列として使用している場合、スペースの便利な短縮形としてゼロは自動的に32に変換されます。|b基本変換用の組み込み関数は、オペランドを整数の生のリストとしてではなく文字列として扱うため、ゼロの場合は失敗します。

10バイト、ゼロで失敗

Ç┘_A♥∙QZ►╣
{128%m128|b    Unpacked
{128%m         Modulize each by 128
      128|b    Convert from base 128

staxlang.xyzで実行してデバッグしてください!


1
その問題はどこから来たのかわかります。 {:B7)m$:b8にパックされ、同様に機能するように見えますが、の一種のエキゾチックな使用です$
再帰的

@recursiveそれは賢いです。別の回答として投稿してください。
Khuldraeseth na'Barya


2

C(gcc)、48バイト

ビッグエンディアン順の整数を入力として受け取ります。これはバイト配列と同じ順序です。

f(i,j){for(j=0;j|=i&127,i&128;j<<=7,i>>=8);i=j;}

オンラインでお試しください!

C(gcc)、53バ​​イト

バイト配列が必要な場合:

f(c,j)char*c;{for(j=0;j|=*c&127,*c++&128;j<<=7);c=j;}

オンラインでお試しください!


-Osを使用してTIOテストコードをコンパイルすると、最後の2つのケースのみが処理されます。理由を伝えるのに十分なCがわかりません。
qwr

@qwr TIOのデフォルトはで-O0、これにより(通常)戻り値を最初のパラメーターに格納できます。これはコードゴルフの奇妙な機能ですが、より高い最適化レベルでは機能しません。
ErikF

あなたは置き換えることにより、バイトをオフに剃ることができます&128>>7
G.スリーペン

2

MathGolf、14 バイト

ê♣%hrx♣▬^mÅε*Σ

整数として入力します。

オンラインでお試しください。

これはもっと短くできると思います。MathGolfにはconstantに1バイトのビルトインがあります128が、ベース変換はありません(バイナリ/ 16進数を除く)。

説明:

ê              # Take the inputs as integer-array
 ♣%            # Take modulo-128 on each value in this array
   h           # Push the length of the array (without popping the array itself)
    r          # Pop and push a list in the range [0, length)
     x         # Reverse the array to (length, 0]
      ♣▬       # Take 128 to the power of each value in this array
        ^      # Zip the two lists together to create pairs
         mÅ    # Map each pair to (using the following two commands):
           ε*  #  Reduce by multiplication (so basically the product of the pair)
             Σ # After multiplying each pair, take the total sum
               # (after which the entire stack joined together is output implicitly)

ベースコンバージョンは1日目から表に載っていますが、ベースコンバージョンに関しては、同時に対処したいオーバーホールがいくつかあります。たとえば、16進文字列との間で異なる演算子を変換したくありません。
maxb

2

Pythonの358 49バイト

@Chasと@ ar4093のおかげで-9バイト

lambda x:int("".join(bin(a|128)[3:]for a in x),2)

オンラインでお試しください!

または

lambda x:int("".join(f"{a%128:07b}"for a in x),2)

オンラインでお試しください!

整数のリストを介して入力します。

Pythonのbin関数は、文字列の先頭に「0b」を追加するため、連結する前にそれらを削除する必要があります。また、先頭のゼロは保持されないため、最後のバイトがない場合は追加し直す必要があります。また、先頭のゼロ(最後のバイト以外のすべて)がある場合は、上手。常に最初のビットを設定することで、最初の3文字を削除して完了できることを理解してくれた@Chasに感謝します。

どうやら(@ ar4093によれば)このformat関数は、プレフィックス '0b'を持たないだけでなく、最初のビットを削除し、同時に7文字にパディングすることも許可します。


CGCCへようこそ。これはあなたをより悪いプログラマーにしてくれるでしょう!:)。最初はあなたと同じ考えを持っていました。をbin(a|128)[3:]必要としないので、9バイト節約できますzfill
チャスブラウン

前述のように、format関数を使用すると、9バイトを節約できますbin(a)[2:].zfill(8)[1:]f"{a%128:07b}"
。-


1

Japt10 8バイト

入力を整数の配列として受け取ります。

muIÑ ìIÑ

試してみるかすべてのテストケースを実行してください(チャレンジで使用される入力形式からの両方の変換のヘッダー)

alephalphaのソリューションからインスピレーションを得て、2バイトを節約しました。

muIÑ ìIÑ     :Implicit input of integer array
m            :Map
 u           :  Modulo
  I          :    64
   Ñ         :    Multiply by 2
     ì       :Convert to decimal
      IÑ     :  From base 64*2

1

、11バイト

I↨﹪θ¹²⁸¦¹²⁸

オンラインでお試しください!リンクは、コードの詳細バージョンです。入力を配列として受け取ります。説明:

   θ        Input array
  ﹪ ¹²⁸    Elementwise modulo 128
 ↨      ¹²⁸ Convert from base 128
I          Cast to string for implicit print


1

Windowsバッチ、76バイト

:a
@set/ax="%1&127",y=y*128+x
@if %2. neq . @shift&goto:a
@echo %y%

「0x」で始まるパラメーターとその間のスペース(例:0xC0 0x80 0x80 0x00)を渡します。


よくできました。明らかに、それをテストしている他の誰にとっても、実行と実行の@set y=,ax=間に実行することを確認する必要があります。
640 KB

1
「set y =」だけで十分です。
ピーターフェリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.