ビット操作としては論理左シフトとまったく同じ。違いは「符号付き整数として解釈する」こと。シフトで符号ビットが反転すると、値の符号が逆転するのが落とし穴です。
算術左シフトは、ビット操作としては論理左シフトと完全に同じです。違いは「符号付き整数として値を扱う」だけ。
動作:
・右端には 0 が挿入される
・左端からあふれたビットは捨てられる
・符号ビット(最上位ビット)も普通のビットとして扱う ← ここがポイント
一見すると論理左シフトと同じなのですが、結果の値を「符号付き」として読むので、シフトで符号ビットが変わった瞬間に値の符号が逆転する独特の現象が起きます。
算術左シフトでは、2 の補数表現で負の数を扱うことを前提にしているため、ただビットをずらすだけでなく「符号としての意味を保つ」ように設計されています。とはいえ、実は左シフトに関しては論理シフトと同じビット操作です(右端に 0 を入れて左端からあふれを捨てる)。違うのは「結果を符号付き整数として読む」という点だけ。
・正の数 (MSB = 0):左にシフトしても MSB が 0 のままなら、符号ビットが保持されている = 正のまま × 2^N
・負の数 (MSB = 1) を 2 の補数表現で扱う場合:左に 1 シフトすると上位ビットの 1 はあふれて捨てられ、下位は前にずれていく。負の数 ÷ 2 のシフトは右シフトの仕事で、左シフトは「符号ビットも含めて素直に × 2 する」だけ
例: 1111 1011 (符号付きで −5) を左に 1 シフト → 1111 0110 = −10。符号ビット(最上位)が 1 のままで、確認: −5 × 2 = −10 ✓。
注意点:符号反転が起きるケース。元が正で MSB が 0 → シフトで MSB が 1 に変わると、結果が突然「負の数」と解釈されてしまいます。例: 64 (0100 0000) を左に 1 シフトすると 1000 0000 = −128(オーバーフロー!)。本来 64 × 2 = 128 だが、8 ビット符号付きでは 127 が上限なので符号ビットが立って −128 になる、というバグです。
算術左シフトは符号付き整数の × 2^Nを実現する高速な方法です。10 進数で「左に 1 桁ずらす = × 10」と同じ感覚で、2 進数では「左に 1 ビットずらす = × 2」になります。これは符号付き・符号なしで関係なく成り立つ性質。
・x << 1 = x × 2
・x << 2 = x × 4
・x << 3 = x × 8
・x << N = x × 2^N(オーバーフローしなければ)
CPU にとって乗算命令より圧倒的に速いので、コンパイラは x * 8 のようなコードを自動的に x << 3 に最適化します。ただし掛ける数が 2 のべき乗のときだけ使えるテクニックなので、ふつうの掛け算(× 3 など)はできません。
N ビット算術左シフトは元の値の 2^N 倍になります(オーバーフローしなければ)。この結果は論理左シフトと同じです。