LoginSignup
4
2

More than 5 years have passed since last update.

ビット演算でデータを圧縮しよう

Posted at

注)この記事では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 00100000 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ビットの節約に成功!これはすごい!

まとめ

ビットってすごい

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2