シフト演算で 2 倍 / 半分
2 倍したいだけなのに、重みを全部足し直すのか
0011 を 2 倍したいとします。重みで考えると 2 + 1 が 4 + 2 になるので、答えは 0110 です。ここで、元と答えを見比べてください。桁の中身は何も変わっていません。1 が立っている場所が、そろって 1 つ左へずれただけです。
10 進数で 123 を 10 倍するときも、同じことをしています。右に 0 を 1 つ足して 1230 にするだけで、掛け算の筆算はしていません。基数が 2 なら、同じ動きが 2 倍になります。
左へずらすと、重みが 2 倍になる
桁の重みは、右から 1、2、4、8 と 2 倍ずつ増えていきます。だから 1 が 1 つ左へ動くと、その 1 が背負う意味が 2 倍になります。全部の桁がそろって動けば、数全体が 2 倍です。
<< はこれをそのまま命令にしたものです。
プレーンテキスト
0011 << 1 -> 0110 3 が 6
0011 << 2 -> 1100 3 が 122 つ動かせば 2 倍の 2 倍で 4 倍、3 つで 8 倍です。ずらした数だけ 2 を掛けたことになります。1 を 10 個ずらすと 1024、20 個ずらすと 1048576 で、これが 1 KB と 1 MB の正体です。
右へずらすと、落ちた桁は戻らない
>> は逆向きです。重みが半分になるので、数も半分になります。ただし右端から押し出された桁には行き場が無く、消えます。
プレーンテキスト
1100 >> 1 -> 0110 12 が 6
1100 >> 2 -> 0011 12 が 3
0111 >> 1 -> 0011 7 が 37 を半分にすると 3 です。3.5 にはなりません。落ちたのは重み 1 の桁だったので、結果として小数点以下を切り捨てた形になります。割り算というより「桁を捨てる操作」だと思っておくほうが、答えを外しません。
だから右へずらしてから左へ戻しても、元には戻りません。7 を右に 1 つ、左に 1 つ動かすと 6 です。捨てた桁は復元できないので、往復させる書き方はしないでください。
はみ出した先は、言語ごとに答えが割れる
左へずらしたとき、扱える幅からはみ出した桁がどうなるかは言語によって違います。JavaScript のビット演算は 32 ビットで行われるので、1 を 31 個ずらした時点で符号の桁に届き、正の数のつもりが負の数になります。
右へずらすときの左側の空きも同じです。多くの言語の >> は符号を保つように埋めるため負の数は負のままですが、JavaScript の >>> は 0 で埋めるので、同じ -8 でも結果が大きく変わります。ずらす量が大きいときと、負の数を渡すときは、その言語の幅を先に確かめてください。
要件
- n と k は 0 以上の整数 (k は 30 未満)
- ビット左シフト (<<) を使うこと。*, **, pow は使わない
- 戻り値は整数
入出力例
multiplyByPow2(3, 2) → 12
multiplyByPow2(1, 0) → 1
multiplyByPow2(1, 10) → 1024
multiplyByPow2(5, 3) → 40
multiplyByPow2(0, 5) → 0
multiplyByPow2(7, 4) → 112
multiplyByPow2(1, 20) → 1048576