注)この記事ではC#を使って説明します
ビットについてのお話
圧縮で通信最適化
通信量を減らすメリットとは
- 貧弱な回線でも通信量が減ることでラグが少なくできる
- サーバーに優しい
- 使用者に優しい
ビット演算について
まずビットって何?って人のために
コンピュータにつまっているフラグのこと
よく見かける0!1!みたいなやつ
ビットが8個集まるとバイトに進化する
まずビット演算って何?って人のために
ビットに対して0と1を切り替えたりすること
ビット演算って何が便利なの?という人のために
ビットで20を表すと0001 0100
となる
ビットで10を表すと0000 1010
となる
ビットを05を表すと0000 0101
となる
つまりビットを一つずらすことで2倍、1/2倍ができる!(しかも速い)
やってみよう
ビットにデータを埋めてみる
今回は2 8 10 15
をデータに埋めてみる
まずそれぞれをビットで表すと・・・
02 -> 0010
08 -> 1000
10 -> 1010
15 -> 1111
のようになる
合計で16ビットなので、ushort(符号なし16ビット整数)にまとめてみる
ushort data = 2 | (8 << 4) | (10 << 8) | (15 << 12);
OR演算子とビットシフトを使うことで
2 = 0010
8 << 4 = 1000 0000
10 << 8 = 1010 0000 0000
15 << 12 = 1111 0000 0000 0000
の4つのデータを組み合わせた・・・
1111 1010 1000 0010
という15 10 8 2
のデータが完成する!
ビットからデータを取ってみる
欲しいデータは2 8 10 15
さきほど作ったデータは1111 1010 1000 0010
となっている
まずは右端の4ビットを取り出したい
つまり1111 1010 1000 0010
と0000 0000 0000 1111
で同じ数値の場所(0010
)を取得すれば良い
var data1 = data & 0b1111;
これで0010
(2
)が取れた!
ではこれで右端の4ビットがいらなくなった
なので4ビットを消して再度右端の4ビットを確認する
var data2 = (data >> 4) & 0b1111;
これで・・・1000
(8
)を取得できた!
あとは同じように8,12とビットをずらして右端を取得していくだけ
とても簡単!
全体のソース
ushort data = 2 | (8 << 4) | (10 << 8) | (15 << 12);
var data1 = data & 0b1111;
var data2 = (data >> 4) & 0b1111;
var data3 = (data >> 8) & 0b1111;
var data4 = (data >> 12) & 0b1111;
var text = string.Format("{0}\n{1} : {2} : {3} : {4}", data, data1, data2, data3, data4);
Console.WriteLine(text);
実際に使ってみよう
必要なビット数を調べる
[Player] 最大値一覧
体力:500 MP:250
攻撃力:99
転生回数:10
ランクアップ済み判定:1
それぞれの最大値分だけビットを確保する
500 -> 1 1111 0100(9bit)
250 -> 1111 1010(8bit)
99 -> 110 0011(7bit)
10 -> 1010(4bit)
1 -> 1(1bit)
合計で29ビットになる
なので今回はint(符号付き32ビット)に埋める
調べたビットを元にデータを埋めていく
上で説明した手順と同じようにデータを埋めていく
そして確認で取得まで
//元データ
var hp = 500;
var mp = 250;
var attack = 99;
var reincarnation = 10;
var rankup = 1;
//intに全て埋める
int data = hp | (mp << 9) | (attack << 17) | (reincarnation << 24) | (rankup << 28);
//埋めたデータの確認
Console.WriteLine("HP:" + (data & 0b111111111)); //dataの末尾9bitを抜き出す
Console.WriteLine("MP:" + ((data >> 9) & 0b11111111)); //dataの末尾8bitを抜き出す
Console.WriteLine("Attack:" + ((data >> 17) & 0b1111111)); //dataの末尾7bitを抜き出す
Console.WriteLine("Reincarnation:" + ((data >> 24) & 0b1111)); //dataの末尾4bitを抜き出す
Console.WriteLine("RankUp:" + ((data >> 28) & 0b1)); //dataの末尾1bitを抜き出す
しっかりと1つのintに全てのデータを埋めることができた!
元々のデータを全てintで送っていた場合と比較すると160 - 32 = 128
で128ビットの節約に成功!これはすごい!
まとめ
ビットってすごい