【基本情報技術者を目指す皆様へ】
・今回は2進数の論理シフトと算術シフトについて教えます!
・実際にPythonで計算を行い、疑問の解決につなげます。
コードが知りたい方は目次のソースコードへ飛んでください!
本記事のテーマ
説明
まず、
2進数のbit列を左もしくは右にずらす操作をシフト演算と呼びます
10進数に対して「10倍」、「1/10倍」するのはどういうことか、
例:230
230 * 10 =2300 ←10進数を左にずらしています
230 / 10 =23 ←10進数を右にずらしています
つまり、2進数における左シフトは「2倍」、右シフトは「1/2倍」されることになります。
コンピュータではこのシフト演算を用いてかけ算、わり算を実現しています。
このシフト演算は二つあり、
・符号を考慮しない:「論理シフト」
・符号を考慮した :「算術シフト」
一つずつ説明していきます
論理シフト
論理シフトとは、符号を考慮しないシフト操作です。
ここでのコンピュータは8bitとします。
左シフト(かけ算)
例:00010110(22)←カッコ内は10進数表記
3ビット左シフトさせると
00010110(22)
00010110←←←(??)
こうなります。この空いたところは'0'で埋められ、はみ出たビットは削除されます
結果、
10110000(176)
となります。
先ほど左に1bitシフトは2倍と言いました。なので左に3bitシフトするということは
2倍×2倍×2倍=8倍することになります。
ここで、先ほどの左シフトの計算を見てみますと、
22 << 3 = 22×8 = 176(<<は左シフトの演算子)
きちんと、2の3乗されていることがわかります。
右シフト(わり算)
例:01110000(112)←カッコ内は10進数表記
3ビット右シフトさせると
01110000 (112)
→→→01110000(???)
こうなります。この空いたところは'0'で埋められ、はみ出たビットは削除されます
結果、
00001110(14)
となります。
先ほど右に1bitシフトは1/2倍と言いました。なので右に3bitシフトするということは
1/2倍×1/2倍×1/2倍=1/8倍することになります。
ここで、先ほどの左シフトの計算を見てみますと、
112 >> 3 = 11×(1/8) = 14(>>は左シフトの演算子)
きちんと、1/(2の3乗)されていることがわかります。
まとめ
・nビット左シフトは2のn乗倍
→空いたところは'0'埋め
・nビット右シフトは(1/2)のn乗倍
→空いたところは'0'埋め
注意:今回は桁あふれを考慮しないためにシフトで削除するビットは'0'のみの8ビットを用いました。
算術シフト
算術シフトとは、符号を考慮したシフト操作です。
ここでのコンピュータは8bitとします。
左シフト(かけ算)
↓符号ビット(0:正、1:負)
例:11110110(ー128+118=−10)←カッコ内は10進数表記
2ビット左シフトさせると
↓ここは固定
1|1110110(ー128+118=−10)
11|10110←← (??)
こうなります。符号ビットは固定され、空いたところは'0'で埋められ、はみ出たビットは削除されます
結果、
11011000(ー128+88=−40)
となります。
左に3bitシフトするということは2倍×2倍=4倍することになります。
先ほどの左シフトの計算を見てみますと、
ー10 << 2 = ー10×4 = −40(<<は左シフトの演算子)
きちんと、2の3乗されていることがわかります。
右シフト(わり算)
例:10111000(−128+56=−72)←カッコ内は10進数表記
3ビット右シフトさせると
↓ここは固定
10111000 (−128+56=−72)
1→→→0111000(???)
こうなります。符号ビットは固定、空いたところは'1'で埋められ、はみ出たビットは削除されます。
!!空いたところは'1'で埋めます。今までは0埋めだったので気をつけてください!
なぜ1で埋めるのかは10進数の計算と一緒に確認すればわかります。
結果、
11110111(ー128+119=ー9)
となります。
右に3bitシフトするということは1/2倍×1/2倍×1/2倍=1/8倍することになります。
先ほどの左シフトの計算を見てみますと、
−72 >> 3 = −72×(1/8) = −9(>>は左シフトの演算子)
きちんと、1/(2の3乗)されていることがわかります。
まとめ
・nビット左シフトは2のn乗倍
→空いたところは'0'埋め
・nビット右シフトは(1/2)のn乗倍
→空いたところは'1'埋め
注意:今回は桁あふれを考慮しないためにシフトで削除するビットは
・左シフトの時は'1'
・右シフトの時は'0'
のみの8ビットを用いました。
以上で2進数の論理シフトと算術シフトの説明は終了です!
特に算術シフトは分かりにくいですが、「はみ出たビットは削除」と「空いたところは基本'0埋め'(算術シフトの右シフトだけ'1'埋め)」を覚えておきましょう!
最後にPythonで実際に2進数の論理シフトと算術シフトをしてみたいと思います!
Pythonで2進数の論理シフトと算術シフト
Code
if __name__ == "__main__" :
# 論理シフトと算術シフト
print("---"*5)
print ("論理シフト")
print("---"*5)
print("・左3bitシフト")
a = 0b00010110 # 22
print (bin(a), "<< 3 =", bin(a<<3))
print (a, "* 8 =", a<<3)
print("・右3bitシフト")
a = 0b01110000 # 112
print (bin(a), ">> 3 =", bin(a>>3))
print (a, "* 1/8 =", a>>3)
print("")
print("---"*5)
print ("算術シフト")
print("---"*5)
print("・左3bitシフト")
a = 0b1110110 # 118
a = 0b0001001 # 反転
a = ~a # 符号付きに変換
print(bin(a), a)
print (bin(a), "<< 2 =", bin(a<<2))
print (a, "* 4 =", a<<2)
print("・右3bitシフト")
a = 0b0111000 # 56
a = 0b1000111 # 反転
a = ~a # 符号付きに変換
print (bin(a), ">> 3 =", bin(a>>3))
print (a, "* 1/8 =", a>>3))
出力
---------------
論理シフト
---------------
・左3bitシフト
0b10110 << 3 = 0b10110000
22 * 8 = 176
・右3bitシフト
0b1110000 >> 3 = 0b1110
112 * 1/8 = 14
---------------
算術シフト
---------------
・左3bitシフト
-0b1010 -10
-0b1010 << 2 = -0b101000
-10 * 4 = -40
・右3bitシフト
-0b1001000 >> 3 = -0b1001
-72 * 1/8 = -9
参考資料
・キタミ式イラストIT塾 基本情報技術者 平成31/01年