コンピューターサイエンス入門:理論編
シフト演算で 2 倍 / 半分
この回でやること
シフトで桁の重みが変わる仕組みと、右シフトで失われる情報を例題で確かめます。
- 読む 約 7 分
- 最後にクイズ 1 問
2倍したいだけなのに、重みを足し直すのか
0011 を2倍すると、重み 2 + 1 が 4 + 2 になり、答えは 0110 です。1が立つ場所が、そろって1つ左へずれています。桁を動かす操作をシフトと呼びます。
掛け算でも求められます。ここでは、桁を動かすと値がどう変わるかを読みます。10進数の123を10倍して1230にするように、2進数では右に0を1つ付けると2倍になります。
左へずらすと、重みが2倍になる
重みは右から1、2、4、8と増えるので、1が1つ左へ動くと、その重みも2倍です。左シフトは << で表します。
プレーンテキスト
0011 << 1 = 0110 3が6
0011 << 2 = 1100 3が122桁なら4倍、3桁なら8倍です。ずらす桁数だけ2を掛けます。ただし、この関係は扱えるビットの幅から値がはみ出さない場合のものです。
1を10桁ずらすと1024、20桁なら1048576です。バイト数を2の累乗でまとめる単位は、1 KiBが1024バイト、1 MiBが1048576バイトです。10進数の単位である1 kBの1000バイトとは区別します。
右へずらすと、落ちた桁は戻らない
右シフトは >> で表します。ここでは0以上の整数を考えます。右端から押し出された桁は消え、空いた左側は0になります。
プレーンテキスト
1100 >> 1 = 0110 12が6
1100 >> 2 = 0011 12が3
0111 >> 1 = 0011 7が37を右へ1桁ずらしても3.5にはなりません。2で割った整数の商3を残し、余り1を捨てるのと同じです。
6と7はどちらも右へ1桁ずらすと3です。シフト後の値だけでは元の数を判別できません。
幅と符号は、言語によって違う
JavaScriptのNumber型のビット演算は32ビットで行います。1 << 31 は符号の桁に届き、結果は -2147483648 です。正の数を左へ動かせば、必ず正のまま倍になるわけではありません。
負の数の >> は符号を保つように左側を埋めます。一方、JavaScriptの >>> は0で埋めます。Number型では -8 >> 1 が -4、-8 >>> 1 が 2147483644 です。記号だけで同じ割り算だと思わず、型と符号も一緒に読みます。
例題で確かめる
0以上の値13を右へ2桁ずらし、その結果を左へ2桁戻します。幅からはみ出さないものとします。
プレーンテキスト
1101 >> 2 = 0011 13が3
0011 << 2 = 1100 3が12右シフトで下2桁の 01 が失われ、左シフトでは代わりに 00 が入ります。答えは12です。13 ÷ 4 の整数の商3を4倍しても12になり、元の13には戻りません。