#可変長数値表現とは
可変長数値表現とは、最上位ビットをフラグをして使う数値の表現方法です。
英語ではVariable-length quantityといいます
この技術はMIDIで実装されており、時間管理に利用されています。
#数値の表現
最上位ビットをフラグに使うとは、次のようなことを意味します。
16進数 0x7F(10進数127)を、2進数で表すと、次のようになります。
//わかりやすくするために4桁で区切っています。
0111 1111
16進数0x80(10進数128)は、2進数で表すと、次のようになります。
1000 0000
一番左のビット(最上位ビット)が1になりました。
可変長数値表現では、最上位ビットに1である場合
、次のバイトにもデータがあることを示しています。
可変長数値表現で0x80を表すと
1000 0001 0000 0000
このようになります。
各バイトの最上位ビットを削除するとこうなります
000 0001 000 0000
=10000000
=0x80
単純に、各バイトの下位7ビットを連結すれば、実際の数値を取得することができます。
具体的には、ビット演算子を使えばこう書くことができます。
//ar はバイト配列とする
function decode(ar){
var value=0;
//最上位ビットが1ならループ
while(ar[i]>=0x80){
//1.最上位ビットのみ反転(例:1000 0001 => 0000 0001にする)
var a = ar[i] ^ (1<<7);
//2.前回の値と連結
value = value<<7 | a;
i++;
}
//最後の値を連結
value = value <<7 | ar[i]
return value;
}
var a = ar[i] ^ (1<<7);
の部分について
ビットごとの XOR
オペランドの対応するビットがどちらか一方のみ 1 である各ビットについて 1 を返します。
これを使って、上位1ビットのみを0に反転しています。それ以外のビット(2~8ビット)に変化は起こりません。
ちなみに、1<<7 = 10000000
です。0x80と書いても同じです
前の値と連結するには、前の値を7ビット左にシフトさせ、ORします。
これにより、最上位ビットと、前の値の最下位ビット部分が重なります。
0x81 0x01 となっている可変数値表現を例にとるなら
0x81 = 10000001
0x01 = 00000001
//0x81 と 1<<7 (0x80) のXOR (最上位ビットフラグを0にする)
10000001
10000000
---------
00000001
//0x01と上記の連結
//0000001を7ビット左にシフト
0000001 << 7 = 10000000
//0x01とOR
10000000
00000001
--------
10000001
=0x80
こんな感じです。わかりましたか?
なお、可変長数値表現に変換したい場合は、下記のようにすれば可能です
function convert(val){
var buffer = [];
buffer.push((val & 0x7F));
val = (val >> 7)
while (val > 0) {
buffer.push(0x80 + (val & 0x7f))
val = (val >> 7)
}
array2hex(buffer.reverse());
function array2hex(ar) {
for (var i=0;i<ar.length;i++) {
ar[i] = (ar[i].toString(16) == 0) ? "00" : ar[i].toString(16);
}
return "0x" + ar.join('');
}
}
}
上記コードは下記より引用しました
https://gist.github.com/silentrob/440159