(もともと「Yahoo!知恵袋」の「知恵ノート」だったものを転載しています)
(最終更新日時:2016/5/27)投稿日:2011/10/17
はじめに
現代のコンピュータでは、負の整数を表現する・整数の引き算をするために、「2の補数(complement)」が、よく使われます。
「知恵袋」では、時折り、「補数」についての質問を見かける事がありますが、質問文を見ますと、質問者の方々は、どうにも「掴めていない」という悩みをお持ちのようです。
しかし、私に言わせれば、それは質問者のせいではなく、教え方や、テキストの書き方が悪いのです。 補数による引き算は、決して難しくなく、分かってしまえばとても簡単なものです。
高級な数学理論はさておいて、簡単な言葉だけで「2の補数」による引き算を説明し、きっちり理解していただくのが、このノートの目的です。 いったん挫折してしまった方、いまひとつ自信が持てない方でも、きっと、大丈夫です。
(ただし、すでに2進数での数値の書き方や、足し算、10進数との相互変換などを学んだ方が対象です)
前提
補数を考える時、大前提となるのは、「有効桁数を決める」ことです。 補数という言葉が出てきた時点で、必ず「有効桁数が決まっているんだな」と思わなければなりません。 これは常に心してください。
2進数の「2の補数」
まず、2進数の「2の補数」について、ざっとおさらいしてみましょう。
(「それは、どういうものかは分かってる」と言いたい方もいらっしゃるでしょうが、後の説明で納得をするために、目を通しておいてください)
2進数の「2の補数」は、先頭ビット(MSB)が1なら負数、0なら正数であり、正負を反転させるには、「1の補数」を求めて1を足します。
2進数の「1の補数」は、各ビットが反転した値です。
ここでは仮に、有効桁数8桁の2進数の「2の補数」について考えてみましょう。 たとえば10011001は MSB が1ですから、「2の補数の世界」では負数を表現しています。 これが何の負数なのかを知るには、まず正数にして……つまり符号を反転させれば良いわけです。
10011001
↓各ビット反転(1の補数を求める)
01100110
↓1を足す(2の補数にする)
01100111
この手順を逆にすると、元の10011001が得られます(正→負の符号反転)。
01100111
↓各ビット反転(1の補数を求める)
10011000
↓1を足す(2の補数にする)
10011001
つまり、「2の補数の世界」においては、正数01100111を符号反転して負数にしたものが10011001になります。 正数01100111は10進数では103ですから、10011001は10進数の-103を表す事になります。
(なぜ、こんなものが「負数」として使えるのか? 今のところは、理解出来ていなくても構いません。2の補数、1の補数というものが、どうやって得られるか、それだけ憶えてしまってください)
10進数の「10の補数」
実は、補数という考え方は、私たちが使い慣れている10進数でも、そのまま使えます。 上記の例では有効桁数8桁の2進数でしたが、たとえば有効桁数3桁の10進数の補数について考えてみましょう。
103という10進数があるとします。これの各桁を反転させると、どうなるでしょう。
0123456789
↓
9876543210
上記の「反転」に従うと、103は896になります。 これをとりあえず「9の補数」と呼びましょう(反転の「上下」を足すと9になるから)。
これに1を足すと897になります。 これをとりあえず「10の補数」と呼びましょう(「9」に1を足したから……安易ですが)。
先ほどの2進数でやってみたような操作、「反転させて1を足す」と、どうなるのか、実際に確かめてみましょう。
103
↓各桁反転(9の補数を求める)
896
↓1を足す(10の補数にする)
897
897
↓各桁反転(9の補数を求める)
102
↓1を足す(10の補数にする)
103
先ほどの2進数と同様、「反転させて1を足す」と、ちゃんと「戻り」ました。
さてさて……「えっ?」と思われるかも知れませんが、有効桁数3桁の10進数の「10の補数」において、897は「-103」を表します!
……「何を言っているのか分からない!」、ですか? それでは実際に試してみましょう。 適当な数、たとえば496について、496-103を計算してみます。 当然ですが、496-103=393です。
次に、496+897を計算してみましょう。496+897=1393です。
今、扱っていたのは、有効桁数が3の「10の補数」でした。1393は、有効桁数が3ならば、393です。
なんということでしょう、「10の補数」を使って、ちゃんと496-103=393が計算出来ました! 897は、-103だったのです!(「有効桁数3の『10の補数』の世界」においては)
何だかよく分からないかも知れませんが、でも、これは、ごく当たり前の計算に過ぎません。 次の計算をご覧下さい。
496-103=393
↓両辺に1000を足してみる
496-103+1000=393+1000
↓それって実は・・・「10の補数」!
496+897=393+1000
↓有効桁数3桁だけ見れば・・・
496+897=393+1000
要するに、「3桁を反転させて1を足す」、という操作は、 1000(4桁)から引いた数を求める事と同じなのです。 3桁を反転させたもの同士を(つまり「元の数」と「9の補数」を)足せば999になるのですから、元の数と「10の補数」を足せば当然、1000になります。
これが、「負符号を使わず、10の補数で引き算が出来る」理由です。 2進数だろうが10進数だろうが、その理屈は同じです。
なお、2進数の「2の補数」は、MSB が0か1かで正負を見分けられますが、10進数の「10の補数」は、最上位桁が0~4なら正で、5~9なら負となります。
まとめ
いかがでしょう、10進数で考えてみれば、全く難しい事ではなかったと思います。
10進数が「10の補数」で引き算が出来るように、2進数は「2の補数」で引き算が出来る、ただそれだけの事だったのです。
先ほど書いた事を繰り返しますが、「3桁を反転させて1を足す、という操作は、 1000(4桁)から引いた数を求める事」と等しく、これが、10の補数で引き算が出来る理由です。 引いた数を足せば、それは引き算と同じだからです。 もちろん、これは、2進数であっても、全く同じ事です。
2進数だと、「反転して1を足す」という操作のうち、「反転」が、ちょっと鮮やかすぎて、行為の意味が分かりづらく、それで、「なんだか今ひとつ分からない」のではないでしょうか……私自身、なぜ反転するのかを、きちんと説明しているテキストを、見たことがありません。
また、10進数で考えてみれば全く難しくはないのですが、10進数で説明しているテキストも、私はほとんど見た事がありません。
「反転して1を足す意味は何なのか」、「10進数ではどうなのか」、この2点さえちゃんと説明すれば、「補数で引き算」は、スッキリ理解出来るはずだと私は思います。
付記
【付記.1…呼び方について】
2進数の場合、「1の補数」とか「2の補数」だとか言っていますが、これらは、「10-1の補数」「10の補数」と言う方が、より良い呼び方だと私は考えています。
そもそも2進数には「2が無い」ので、「2の補数」という呼び方は、あまり良いものとは思えません。2進数の10-1は1です。 1の補数とは、各桁の和が1になる数であり、2の補数とは、1の補数に1を加えた数です。
10進数の10-1は9です。 9の補数とは、各桁の和が9になる数であり、10の補数とは、9の補数に1を加えた数です。つまり、何進数であろうが、「10-1の補数」「10の補数」と言えば、必ず通用します。
……が、この呼び方は、私の知る限り、ほとんど使われていません。 今後、「1の補数」「2の補数」という言葉を聞いたら、「ああ、これは『10-1の補数』『10の補数』という意味なんだな」と考えていただければ、より分かりやすいと思います。
【付記.2…なぜ「2の補数」を使うのか】
ご存じの通り、コンピュータの中身は、電子回路です。 電子回路で、2進数1桁の足し算を作るのは、難しい事ではありません。 この回路を連結すれば、多ビットの足し算回路になります(ビットを反転させる回路は、さらに簡単です)。
しかし、引き算回路をまじめに作ろうとすると、桁借りがあったり、負符号をどうするのかという問題が出てきます。「2の補数」の考え方を使えば、足し算回路と反転回路だけで、引き算回路が簡単に実現出来ます。 これは便利で、しかも高速なので、現在のコンピュータは、2進数の「2の補数」をよく使うようになったのです。
【付記.3…他の方法】
負数を表現する方法は、他にもいくつかあります。 「符号に1ビットを割り当てて、他のビットは絶対値だけを扱う」のも1つの方法ですし、「有効桁数の中で、全ての整数を『ずらして』しまい、負数を扱わない」(下駄を履かせる、バイアスをかける、などという)方法もあります。
また、小数を含む実数を扱うには浮動小数点がよく使われており、多くの浮動小数点は符号を数値と独立して保持しています。
しかし、2進数回路を基本とするコンピュータにおいては、整数の加減算には「2の補数」を使うのが簡単で高速です。
【追記(2012/10/16)】
monhanpapaia さんから、「変換方法だけでなく『なぜ2の補数を使うと足し算で減算が出来てしまうのか』、その理論が欲しい」とアドバイスをいただきました。
本ノートの「まとめ」の直前に、「3桁を反転させて1を足す、という操作は、 1000(4桁)から引いた数を求める事と同じ」だと私は書いております。 この「3桁」とか「4桁」とか「1000」というのは、2進数だろうが3進数だろうが10進数だろうが同じ事なのです。
補数を使う時に不可欠なのは、本ノートの「前提」ですでに書いた通り、有効桁数を決めておく事です。 上記で書いた事は、「有効桁がnならば、n桁の数値を反転させて1を足すのは、n桁の最大値+1から引いた数を求めるのと同じ」、と言い換えられます(たとえば10進数におけるn桁の最大値+1は、nが3なら、999+1すなわち1000です)。
「引いた数」を足す、という計算は、減算と同義です。 従って、2の補数(私は10の補数と呼ぶことを提案しております)の加算は、減算と同義になるのです。
(転載以上)