みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

2進数ビット列の算術シフトについて

技術者向けでは基本的すぎて笑われてしまうかも知れません。が、プロの方で詳しい方にお聞きしたかったのです。例えば、プラスの数値を算術右シフトすれば
「あふれたビットを破棄するのは、その範囲で表現できないから切り捨てる。
たとえば3を2で割ると1.5ですが、
1右シフトすると1になりますが、
0.5を保持する桁がないからですね。
逆に桁あふれも同じ意味ですね。」という回答を見たのですが、確かにプラス部(負数でない部分)については理解出来るのですが、これがマイナスの整数(電算機上では負数)の場合、例えば「-1.5」であれば「-2」になるということでした。なぜ単純に「-0.5」部分の切り捨てで済まないのでしょうか?

投稿日時 - 2009-05-21 18:44:21

QNo.4978371

すぐに回答ほしいです

質問者が選んだベストアンサー

No.1です。

>どうしても分からないのは、(中略)つまり絶対値で0.5の差が出る理由です。
くどくなりますが、すべては『2の補数を使用するから』というところに集約します。

以下は4bitで説明します。
4bitの場合、表せる範囲は「0000」~「1111」の16種類です。
正負の数を「1の補数」で表現した場合
 0000:0   1111:0(本来は使用しないが扱い上は0)
 0001:+1  1110:-1
 0010:+2  1101:-2
 0011:+3  1100:-3
 0100:+4  1011:-4
 0101:+5  1010:-5
 0110:+6  1001:-6
 0111:+7  1000:-7
となります。「-7~0~+7」までの「15」の数値を表します。
対して「2の補数」は
 0000:0   1111:-1
 0001:+1  1110:-2
 0010:+2  1101:-3
 0011:+3  1100:-4
 0100:+4  1011:-5
 0101:+5  1010:-6
 0110:+6  1001:-7
 0111:+7  1000:-8
となります。「-8~0~7」までの「16」の数値を表します。
つまり、+(0も含む)と-で表現できる範囲が1つずれているのです。

あえて誤解するように書けば、「0」が中心ではなく「-0.5」がデータ的な中心です。
絶対値は、データの中心である「-0.5からの相対位置」になりますから「+1」の絶対値なら「1.5」、「-1」の絶対値は「0.5」、絶対値の差は「1」となります。
この値を「プラスとマイナスだから/2」とすると「0.5」になります。
それによって発生する問題です。

正直なところ、なんとか理屈づけて納得しようとしても難しいので「こういうものだ」と割り切ったほうがいいと思います。

投稿日時 - 2009-05-22 19:41:26

お礼

ほんとうにご丁寧に分かりやすい解説有難うございました。SilverThaw
様の親切さにただ感涙するのみです。感謝いたします。

投稿日時 - 2009-05-22 20:50:38

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

No.1です。
>(1)n進数の補数にnの補数とn-1の補数の二つがある理由が分かりません。
正直、私も知りたいです。
このおかげで私も過去に「2の補数」のつもりで作っていたら、実は「1の補数」でイタイ目を見たことがありますので(単に、仕様の確認漏れだけなのですが)
個人的な考えですが、
・単純にわかりやすくビットを反転しただけ(+1の処理がいらない、回路も小さくなる)
・「0000 0000」を起点として「0000 0001」「0000 0010」……と、「1111 1111」「1111 1110」……と進んでいくのがわかりやすいから
ではないかと考えたりしてますが。

>(2)一番分からないのは、このシステムで100を2進数で8ビットで表したものを(後略)
結論から書くと「10進数」ではなく「2進数(2の補数表現)」で処理しているためです。
単純に10進数で算出した際の小数点を切り捨てているわけではありません。
「2進数(2の補数)」で考えるとすっきりします。

今までと同じく8bit表現で記載します。
「+100」は「0110 0100」、「-100」は「2の補数」では「1001 1100」で表されます(算出方法はNo.3参照)。
これを「右に3ビット算術シフトする」と
「0110 0.100」(+100)は「0000 1100」=「12」
「1001 1.100」(-100)は「1111 0011」
となります(上記はわかりやすくするために、シフトした際に一番下位のbitの位置に「.」をつけています)。
この「1111 0011」は「1111 1111」(-1)から数えて13番目であり「-13」となります。
(尚、マイナス値からの絶対値を求める場合も、「bitを反転して+1」は同じです。)

投稿日時 - 2009-05-22 11:36:17

補足

ご丁寧に毎回詳しいご回答を本当に有難うございます。ただ悲しいですけど、自分には向かないのか・・・どうしても分からないのは、(1)+100を2進数で8ビットで表したものを右に3ビット算術シフトする場合は+12になり(2)-100を同じように処理した場合、-13になる、つまり絶対値で0.5の差が出る理由です。甘えすぎかも知れませんが、もし、可能でしたら、是非ご教授下さい。

投稿日時 - 2009-05-22 18:33:26

ANo.3

No.1です。

>(前略)(残ったビットを10進数表示した場合の絶対値が、正負でことなる理由が分からないのです)もしよろしければご教授願います。
結論から書くと「マイナス値を表す手法が『2の補数』基準」で考えているからです。

まず、「2進数」は理解されていますか?
また、「マイナスを表すための方法」については?
ここが理解できていないと難しいです。

以下は8bitの2進数で説明します。
10進数の「+3」は2進数では「0000 0011」と表します。
これを右に1bitシフトすれば「0000 0001」となります。
一番下位ののbitが追い出されるため、結果は「1」となります。

対して「-3」は「2の補数」で表すと「1111 1101」となります。
「2の補数」はマイナス値を表す方法の一つで、正の値のbitの0/1を逆転した値「+1」することで値を表します。
これにより、マイナス値の場合は必ず最上値のbitが「1」になります。
「-3」の場合は「0000 0011」をbit反転して「1111 1100」、それに「+1」して「1111 1101」となります。
この値を右に右に1bitシフトすれば、桁あふれし「1111 1110」となります。
「2の補数では」この値は「-2」です。

ちなみに、マイナス値の手法には「1の補数」というものも存在します。
この場合「-3」の値は「1111 1100」。
右に1bitシフトした値は「1111 1110」となり、結果は「-1」となります。

投稿日時 - 2009-05-21 20:41:49

補足

ご丁寧に詳しい補足説明有難うございます。確かにまだ理解が曖昧な部分あると思います。もし更に教えていただけるなら(1)n進数の補数にnの補数とn-1の補数の二つがある理由が分かりません。(2)一番分からないのは、このシステムで100を2進数で8ビットで表したものを右に3ビット算術シフトする場合と-100をこの補数表現で同様の行為(右に3ビット算術シフトする)を行った場合とで+と-の符号を除いた絶対値に違いが出ることです。前者は10進数表記では12.5から小数点以下の0.5(2進小数点以下の1ビット)を切り捨て、12?後者もやはりこの算術シフトによる右の桁の切り捨てで小数点以下のビットは消えるはずなのに-13?(絶対値13)?+と-では0と1は反転するのは分かるのですが、この計算結果になるロジックが分からないのです?

投稿日時 - 2009-05-21 21:59:30

ANo.2

「負の数の丸め」は表現として微妙なところがあります.
たとえば「-1.5 を整数に丸める」ときに「-2 とする」のか「-1 とする」のかという選択があります. 実際には正の場合にも選択肢が考えられます. ということで, 丸めの方法には
・負の無限大への丸め (小さい方に丸める)
・正の無限大への丸め (大きい方に丸める)
・0 への丸め (絶対値の小さい方に丸める)
・最近値への丸め (最も近い値に丸める: 中間のときは偶数にするのがきっと正しい)
などがあります.
今の場合は「負の無限大への丸め」となるので -1.5 が -2 になります.
解釈によっては「-1.5 を -2 にするのは -0.5 の部分を切り捨てたんだ」とも見なせますけどね.

投稿日時 - 2009-05-21 19:05:40

補足

すみません。丸めというよりは単純に算術右シフトした場合に、小数点以下にあたるのビットを切り捨てねばならない場合のことです。

投稿日時 - 2009-05-21 19:17:40

ANo.1

「(-3)÷2」とした場合、8bitでの-3の「2の補数」は2進数で表すと「1111 1101」。
「2で割る」ことにより、右に1bitシフトした値は「1111 1110」。
これは「-2」にあたるから。

投稿日時 - 2009-05-21 18:54:04

補足

早速のご回答有難うございます。ただ小数点以下を表示しないビット列で右算術シフトした場合でビットが一つ溢れた場合、プラス部なら0.5にあたるビットの切り捨てとかで理解出来るのですけれども、負数で
はなぜ単純に-0.5に当たるビットの切り捨てとならないのでしょうか?(残ったビットを10進数表示した場合の絶対値が、正負でことなる理由が分からないのです)もしよろしければご教授願います。

投稿日時 - 2009-05-21 19:08:20

あなたにオススメの質問