読者です 読者をやめる 読者になる 読者になる

オルトプラスエンジニアの日常をお伝えします!

通信量を減らすビット演算

※この記事は「AltPlus Advent Calendar 2016」の19日目の記事です。 こんにちは。オルトプラスの福原です。

昨今誰でも簡単にアプリが作れる環境が整い、手軽に開発も出来るようになってきました。中でもリアルタイムで通信を行い複数人数で遊ぶアプリも増えてきています。 ここで注目しておきたいのは通信量です。いくらネットが普及し光回線設備が整ったとしても無制限ではありません。一度に送受信できる量の限界、光の速度の限界は当然あります。 今現在、スマートフォンではキャリアが設けた通信量の制限にすぐ到達してしまわないように配慮する必要が出てきます。そして運営している側から見た場合、サーバーのデータ転送量を極力下げコストを抑えたいところでもあります。

どのような方法があるか

通信する量を減らすかまたは極力通信を行わなくても済むような設計が必要になると思います。今回は前者の量を減らすという部分について述べてみます。 お手軽な方法はデータ(jsonなど)を圧縮して送る方法ではありますが、今回はもっと根本的な部分から見てみることにします。 ほぼ全ての言語で利用可能なビット演算^1です。

1 バイトの中身

ビット番号 7 6 5 4 3 2 1 0
対応値 128 64 32 16 8 4 2 1
0 0 0 0 1 1 1 0

上記は整数 14 を表します。

例1

4人でデータの送受信を行ったケースを見てみます。 この例ではサーバーで4人のマップ上の X 座標、Y 座標を収集しを4人へ送ることとします。

map00.png

X 座標を float 型 4 バイト y 座標を float 型 4 バイト

1回の送信で

8 bytes x 4 = 32 bytes

4人分で 32 bytes になります。

これを JSON 表記した場合^2

{
  "player1" : { "x" : 350.48, "y" : 190.66 },
  "player2" : { "x" : 80.21, "y" : 200.34 },
  "player3" : { "x" : 128.93, "y" : 260.66 },
  "player4" : { "x" : 288.19, "y" : 90.12 }
}

この例では大体の位置が分れば良い前提として、 左上からマップを 16x16 のブロックで分割しておき、対応する座標から対象となるブロックを xy の座標としてしまいます。

map00.png

{
  "player1_xy" : 107
}

このように他のユーザーの座標も含めると以下のようになります。

{
  "player1_xy" : 107,
  "player2_xy" : 119,
  "player3_xy" : 187,
  "player4_xy" : 76,
}

このデータをさらに短くするためビット演算を使うと以下のように一つの整数にすることができます。

なぜ 1803008844 になったのかと言うと、4つの値をビット演算を用いて1つの 32bit 整数へ入れたため

01101011 (107) << 24 bit 左へシフト = 1795162112
01110111 (119) << 16 bit 左へシフト = 7798784
10111011 (187) << 8 bit 左へシフト = 47872
01001100 (76) はそのまま
ビット位置 24 16 8 0
元の値 107 119 187 76
1進数 01101011 01110111 10111011 01001100
ビット数 8bit 8bit 8bit 8bit

それぞれを左へシフトすることで 01101011 01110111 10111011 01001100 = 計 32 bit 整数 = 1803008844 となります。

結果を JSON 表記した場合[^3]

{
  "player_positions" : 1803008844
}

4人の座標データが一つの 32bit 整数にまとまりました。 この整数を逆に右シフトなどさせてそれぞれのプレイヤーの座標を取り出すことになります。

まとめ

最初の 32bit float 型 8 個のものより、 1/8 ほど通信量を減らせたと言えます。 特にリアルタイムで何度も送受信するケースでは重宝してくるでしょう。 極端な例でしたが適切な要所で扱えればかなりの量が節約できてしまうビット演算でした。

では今回はこの辺りでまた次の機会に。