- 締切済み
算術シフト演算が成り立つ理由がイマイチ・・・
算術シフト演算で右シフトにしても左シフトにしてもシフトで空いたビットに符号ビットと同じ物を入れたり0を入れたり、溢れたビットを破棄したり・・・ というのがどうして成り立つのかがイマイチわかりません。 手元の本を見てもWebで探してもそういうことは細かく書かれていなくてよくわからないのです。 レポートで書かなければいけないのにこのままでは答えが出るのが間に合いそうもなく助けを借りたいと思い質問させて頂きました。 どなたかわかる人が居ましたらよろしくお願いします。
- みんなの回答 (8)
- 専門家の回答
みんなの回答
>最上位ビットの符号ビットはそのままというのはわかるのですが、そのすぐ下位のビットで符号ビットと同じものを補充する・・・のつもりで書いていたのです。 4ビットの各桁をABCDとすると、 ・ABCDを右にシフトすると ?ABC になる。 ・?の部分は シフトする前の値の同じ場所にあった桁をそのままもってくるので AABC になる。 ですから「そのすぐ下位のビットで符号ビットと同じものを補充する」わけではありません。 A B C D 元の数値 |\\ \ A A B C シフト1回目 |\\ \ A A A B シフト2回目 |\\ \ A A A A シフト3回目 ↑この図は当幅フォントで見てください。
>右シフトの場合で最上位の符号ビットと同じものを空いた上位ビットに補充というのが未だに理由がイマイチわからないです。 符号を保存するためです。 右シフトをしたとき最上位ビットに入れる数の候補は ・0を入れる。 ・1を入れる。 ・符号ビットと同じものを入れる の3つがありますが、それぞれについて比較すると分かります。 4ビットで解説します。 例 0100(10進で4)の場合 ・0を入れる 0010 (10進で2) ・1を入れる 1010(10進で-6) ・符号ビットと同じものを入れる 0010 (10進で2) 例 1100(10進で-4)の場合 ・0を入れる 0110 (10進で6) ・1を入れる 1110(10進で-2) ・符号ビットと同じものを入れる 1110 (10進で-2) つまり、正の数でも負の数でも「右シフトすると1/2」になるという理屈に合うのは、 「符号ビットと同じものをいれる」 ときだけなのです。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>右シフトの場合で最上位の符号ビットと同じものを空いた上位ビットに補充というのが #1の対応表を見て下さい。 最上位ビットがあるものをマイナスとして表現しているのがわかるでしょう。 丁度符号付きの数値として、考えた場合でも(1算術右シフトは、値を半分にする)値が半分になっていることがわかると思います。 もし、符号ビットがシフトによって補充されない(論理シフト)なら、マイナスの表現として破綻してしまいます。(割った結果が正になるから)このことも、#1の対応表をみればよくわかると思います。
数字の右端に小数点があると考えるとわかりやすいと思います。 10進数では左にシフトすると10倍、右にシフトすると1/10となるのと同じで、 2進数では左にシフトすると2倍、右にシフトすると1/2となります。 10進で5の例 05.00を、左シフトすると50.00(=10倍)、 右シフトすると00.50(=1/10) 2進で0101の例 0101.0000を、左シフトすると1010.0000(=2倍)、 右シフトすると0010.1000(=1/2) つまり、n進数で表した数値は、左シフトでn倍、右シフトで1/nになります。 但し、2進数では 1 算術右シフトと論理右シフトでは結果が違う。 2 負の数を補数で表現するため、右シフトでは最上位ビットを保存する必要がある。 3 少数は別の形式(浮動小数形式)で表現するため、小数点より右側はカットする。 という違いがあります。
補足
左シフトについては理解しました。 右シフトの場合で最上位の符号ビットと同じものを空いた上位ビットに補充というのが未だに理由がイマイチわからないです。 自分でも考えてはいますがナカナカこれだ!って理由が出てこないです。こういうもんだと思って覚えろと言えばそれまでかもしれないですが・・・
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
C言語で、左シフトで算術シフトと論理シフトが区別がないのは、 1シフトが2倍になるという意味(つまり算術シフト)の時、 シフトの結果が、表現できる範囲の時、 (表現できない場合は、桁あふれしているので、意味がない) (論理シフトと)同じ結果になるためです。 例えば、16ビットの時 -32768~32767の範囲で結果が収まる時、正しい結果になるということですね。
お礼
言われてみれば確かにそうですね。表現できない範囲にシフトするとどちらも論理/算術で壊れ方は違っても意味が無くなるということですね。 わからない(気がつかなかった)とこが1つ減ってすっきりしました。
- JaritenCat
- ベストアンサー率37% (122/322)
シフト演算には、論理シフトと算術シフトがあります。算術シフトでは符号ビットが保持されますので、負数をシフトした場合両者の値が変わってきます。どうして成り立つかと聞かれてもそういうきまりなので答えようがありません。 ちなみに、C言語で書く場合、signed型を右シフト(>>)すると算術シフト、unsigned型を右シフトすると論理シフトになります。左シフト(<<)は論理シフトです。算術シフトしたければ符号ビットを保持しておいてor(|)するか、インラインアセンブラを使います。(僕が知らないだけかもしれません。算術左シフトの書き方があったら教えて欲しいです。)
補足
基本情報の対策テキストを見て勉強していたのですがCには算術左シフト無いんですか。。 情報系のカテゴリの中でC言語の場合応用分野が広い分こういうこと説明できる人も多いかなと思ってこのカテゴリに投稿させて頂きました。不適切だったでしょうかね・・・
成り立つというのは何を指しているのですか? 算術左1ビットシフトは値を2倍にします。8ビットで100*2が負数になってしまうのと同じように、左シフトで符号ビットが壊れることもあります。 算術右1ビットシフトは値を1/2にします(ただし、-1を右シフトした場合だけうまくいかない)。符号ビットがそのまま残るのは符号を変えない為です。
補足
算術左・右シフトの場合も符号ビットはそのままというふうに理解していたのですが正負が変わるというようなことはあるのでしょうか?
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
例えば、仮に、4ビットで考えてみると最上位ビットを符号ビットとして考えると 1111→-1 1110→-2 1101→-3 1100→-4 1011→-5 1010→-6 1001→-7 1000→-8 0111→7 0110→6 0101→5 0100→4 0011→3 0010→2 0001→1 0000→0 だとすると、 -8を1算術右シフトすると-4になりますよね。 これは、左シフトが2倍右シフトが1/2倍ということに合いますよね。 あふれたビットを破棄するのは、その範囲で表現できないから切り捨てる たとえば 3を2で割ると1.5ですが、 1右シフトすると1になりますが、 0.5を保持する桁がないからですね。 逆に桁あふれも同じ意味ですね。
お礼
具体的な例ありがとうございます。 やはり溢れたビットを破棄と言っても意味のあるビットが上位に含まれるときはダメなんですね。左シフトの場合は理解できました。
補足
すいません。表現マズかったです。 最上位ビットの符号ビットはそのままというのはわかるのですが、そのすぐ下位のビットで符号ビットと同じものを補充する・・・のつもりで書いていたのです。