情報系資格の教本を何気なく見ていて、ビットシフトの項目でふと気になった・・・Javaのビットシフト・・・なんか変じゃない・・・?
Javaのシフト演算子
演算子 | 意味 |
---|---|
<< | 符号無し左シフト |
>> | 符号付き右シフト |
>>> | 符号無し右シフト |
なぜ>>>
の記号を左右反転した<<<
が存在しないのか・・・
なぜ<<
が符号無しシフトなのに、記号を左右反転した>>
が符号付きシフトなのか・・・
シフト演算の種類
論理シフト
・空いたビットは0を入れる
2進数 | Javaの演算子 | |
---|---|---|
もとの値 | 1010 1010 1010 1010 | - |
←1論理シフト | 0101 0101 0101 0100 | << |
→1論理シフト | 0101 0101 0101 0101 | >>> |
算術シフト
・最上位ビット(符号ビット)は固定
・左シフトの場合、空いたビットは0を入れる
・右シフトの場合、空いたビットは最上位ビットと同値を入れる
2進数 | Javaの演算子 | |
---|---|---|
もとの値 | 1010 1010 1010 1010 | - |
←1算術シフト | 1101 0101 0101 0100 | - |
→1算術シフト | 11 010101 0101 0101 | >> |
左算術シフトが無いのはそもそもプロセッサのせい?
こんな記事を見つけた
これはJavaに限った話ではなく、より一般的に「2の補数表現を採用している(=つまり殆どの)プロセッサー」の機械語の命令セットの仕様でも同様だと思います。(むしろそこに仕様の本質があると思います)
どうやら(<<<
に対応する?)左算術シフトが無いのは、プロセッサ自体が左算術シフトに対応していないかららしい。(詳しくは引用元で解説されています)
要は左算術シフトは余分な処理が必要になるということのようだ。
(らしい とか ようだ とか曖昧なのは完璧には理解していないから)
論理シフト、算術シフトで語るのが間違い?
これも先程の記事から引用
シフトは「ビット列を負号無し整数値としてとらえた際に2のべき乗で乗算したり除算したりすることと同義」という特徴があります。「2の補数表現」の場合は上記を簡単に「負号あり整数」に拡張することができます。
試しに計算してみる
10進数 | 2進数 | 備考 | |
---|---|---|---|
value | -1431655766 | 1010 1010 1010 1010 1010 1010 1010 1010 | valueはint型整数 |
value * 2 | 1431655764 | 010 1010 1010 1010 1010 1010 1010 10100 | 正しい解は-2863311532 int型の最小値は-2147483648 オーバーフローしている |
value << 1 | 1431655764 | 010 1010 1010 1010 1010 1010 1010 10100 | = value * 2 |
value / 2 | -715827883 | 11010 1010 1010 1010 1010 1010 1010 101 | |
value >> 1 | -715827883 | 11010 1010 1010 1010 1010 1010 1010 101 | = value / 2 |
value >>> 1 | 1431655765 | 01010101010101010101010101010101 |
つまり、
<< n
は * 2n
>> n
は / 2n
と対応している。
「なぜ<<
が符号無しシフトなのに、記号を左右反転した>>
が符号付きシフトなのか・・・」という疑問は、論理シフトや算術シフトを基準に考えるのがそもそも間違っていたという事だった。