FE EXAM

2の補数

コンピュータが負の整数を表現する方法

TWO'S COMPLEMENT
MSB
反転
10進数
-5
ビット列
11111011
符号なし解釈
251
表現範囲
-128 〜 127
10進数-5
-128127
ビット数
プリセット
解説

📌
2の補数とは

コンピュータの中では全てが0と1+5 = 00000101-5 = 11111011正の数はそのまま負の数は2の補数で表す最上位ビット(MSB) 0=正, 1=負

私たちは「-5」と書けば負の数だとわかりますが、コンピュータは0と1しか扱えないため、マイナス記号「-」を直接表現する手段がありません。0と1だけで「この数は負です」と表すにはどうすればよいでしょうか? その答えが2の補数という仕組みです。現在のほぼすべてのコンピュータがこの方式を採用しています。

基本的なルールは2つだけです。
最上位ビット(MSB)で正負を判定する:一番左のビットが0なら正の数、1なら負の数。8ビットなら左端の1ビットが符号、残り7ビットが値を表します
負の数は「ビット反転+1」で作る:例えば+5(00000101)の負版を作るには、まず全ビットを反転して11111010、そこに1を足して11111011。これが-5です

実際に-5を作ってみましょう。
・+5のビット列:00000101
・全ビットを反転(0→1、1→0):11111010
・1を足す:11111011 ← これが-5
検算として、+5と-5を足してみると 00000101 + 11111011 = 100000000。先頭の1は8ビットからはみ出す(オーバーフロー)ので捨てると00000000 = 0。+5 + (-5) = 0 が正しく成立しています。

8ビットの2の補数で表せる範囲は-128〜+127です。
正の側:00000000(0)〜 01111111(127)
負の側:10000000(-128)〜 11111111(-1)
合計:256個(2の8乗)の値を表現できます
上のスライダーで正と負の数を切り替えて、MSB(赤くハイライトされるビット)の変化とビット列全体がどう変わるか確認してみてください。

🛠
求め方の手順

Step 1: 絶対値の2進数00000101Step 2: ビット反転11111010Step 3: +1 → 2の補数11111011

2の補数の求め方は「ビット反転して1を足す」の2ステップだけです。-5 を8ビットで求める手順を丁寧に追ってみます。

Step 1: 絶対値を2進数にする
5を2進数に変換します → 00000101
(8ビットなので先頭を0で埋めて8桁にします)

Step 2: 全ビットを反転する
0を1に、1を0に、すべてのビットをひっくり返します。
0 0 0 0 0 1 0 11 1 1 1 1 0 1 0
この時点の値を「1の補数」と呼びます。ここで止めると+0と-0の問題が出るため、もう1ステップ必要です。

Step 3: 1を足す
11111010 + 1 = 11111011
これが-5の2の補数表現です。

逆変換(2の補数 → 元の値)も同じ手順です。11111011 のビットを反転して 00000100、1を足すと 00000101 = 5。つまり「ビット反転+1」を2回やると元に戻ります。負の数が与えられたとき、同じ操作で絶対値がわかるのは非常に便利です。

もう1つ例を見てみましょう。-1 を8ビットで表すと?
・+1 = 00000001 → 反転 → 11111110 → +1 → 11111111
-1は全ビットが1になります。これは「最大値+1 = 0(オーバーフロー)」と考えると直感的です。上のツールで負の数を入力すると、この3ステップがアニメーションで確認できます。

💡
なぜ「反転+1」で負になるのか

4ビットの時計(0〜15が一周)01234567-8-7-6-5-4-3-2-1+5 と -5 は足すと 16(= 一周=オーバーフロー = 0)

「なぜビットを反転して1を足すと負の数になるのか?」。手順として覚えることはできても、なぜそうなるのかを理解しておくと、丸暗記より格段に応用が利きます。

鍵になるのは「時計の仕組み」です。4ビットで表せる値は 0〜15 の16通り。これをアナログ時計のように円に並べると、15の次は0(オーバーフロー)になります。この性質を使うと、「引き算」を「足し算」で表現できます。
「5を引く」 = 「16 - 5 = 11 を足す」:どちらも時計を同じ量だけ動かすから
5 + 11 = 16 → 4ビットではみ出した1を捨てると 0000 = 0
・つまり 11(= 1011)は、4ビットの世界での -5 として使える

この「16 - 5 = 11」を計算するとき、実は「全ビット反転 + 1」と同じ結果になります。なぜなら全ビット反転は「15から引く(15 - 5 = 10)」と等しく、そこに1を足すと「16 - 5 = 11」になるからです。
15 = 1111(4ビット全部1)
1111 - 0101(5)= 1010(10) → これが「全ビット反転」
1010 + 1 = 1011(11) → これが「+1」
こうして「反転+1」は、nビットの最大数+1(繰り上がり = 0)から元の数を引いた結果を得る最短の手順なのです。

💡
負数表現として使われる理由

引き算を足し算で処理できる5 - 3 = 25 + (-3) = 200000101 + 11111101 = 00000010加算回路だけで引き算も実行可能

負の数を表す方法は他にも「符号ビット方式(先頭ビットで正負だけ変える)」や「1の補数」がありますが、現代のコンピュータはほぼすべて2の補数を採用しています。その最大の理由は引き算を足し算として処理できることです。

具体例で見てみましょう。「5 - 3」を計算したいとき、2の補数を使うと次のように変換できます。
・5 - 3 を 5 + (-3) と書き換える
・-3の2の補数は 11111101
・00000101 + 11111101 = 00000010(= 2)
普通に足し算するだけで、引き算の答えが正しく出ます。CPUの中に「引き算専用の回路」を作る必要がないのです。足し算回路1つで加減算の両方をこなせるため、ハードウェアがシンプルになり、計算速度の向上とコスト削減に直結します。

2の補数にはもう1つ重要な利点があります。「0」の表現が1つだけであることです。符号ビット方式では +0(00000000)と -0(10000000)の2つのゼロが存在し、「0と0は等しいか?」の判定が面倒になります。1の補数でも +0(00000000)と -0(11111111)が生まれます。2の補数では 00000000 が唯一のゼロで、この問題が発生しません。

📌
符号ビット方式(符号と絶対値)

先頭ビットを符号にするだけ+5 = 00000101-5 = 10000101先頭0 = 正先頭1 = 負(残りはそのまま)

ここからは、2の補数以外に考案された「負の数の表し方」を紹介します。2の補数がなぜ最善なのかは、他の方式の問題点を知ると一層よくわかります。

まずは最もシンプルな符号ビット方式(符号と絶対値)です。先頭の1ビットを「0なら正、1なら負」という符号に使い、残りのビットは絶対値をそのまま入れます。人間がマイナス記号を書くのと同じ発想です。

例えば8ビットの場合:
・+5 = 00000101(先頭0 = 正、残り7ビットで5)
・-5 = 10000101(先頭1 = 負、残り7ビットで5)

わかりやすいですが、致命的な問題が2つあります。
+0と-0が存在する:00000000(+0)と 10000000(-0)。同じゼロなのに2種類あり、比較のたびに特別処理が必要
加算回路で引き算ができない:5 + (-5) を単純に足すと 00000101 + 10000101 = 10001010(-10)で間違い。符号を見て場合分けする専用回路が必要になる
この問題を解決するために、1の補数、そして2の補数が考案されました。

📌
1の補数

全ビットを反転するだけ+5 = 00000101-5 = 11111010元の値0と1を全部ひっくり返す

1の補数は、符号ビット方式の「加算で引き算ができない」問題を改善した方式です。求め方はシンプルで、すべてのビットを反転する(0→1、1→0)だけです。

1の補数なら、足し算で引き算ができるようになります。5 + (-5) を試してみましょう:
・00000101 + 11111010 = 11111111
・11111111 は -0(全ビット1)。数学的には0なのでほぼ正解ですが、ここに問題があります。

1の補数の問題点:
+0(00000000)と-0(11111111)の2つのゼロがまだ存在する。符号ビット方式と同じ問題が残っている
桁上がり補正(エンドアラウンドキャリー)が必要:最上位ビットから桁上がりが出た場合、その1を結果に足し戻す追加処理が要る。例えば 3 + (-1) = 00000011 + 11111110 = 100000001 → 先頭の1を末尾に足して 00000010 = 2
この2つの問題を、「ビット反転の後に+1する」というたった1ステップの追加で解決したのが2の補数です。

📌
3つの方式を比較

負の数の表し方には歴史的に3つの方式がありますが、現在使われているのは2の補数だけです。なぜ2の補数が勝ち残ったのかが、この表で一目でわかります。

符号ビット方式1の補数2の補数
求め方先頭ビットを1にビット反転ビット反転+1
-5 (8bit)100001011111101011111011
ゼロの数+0と-0の2つ+0と-0の2つ1つだけ
範囲 (8bit)-127〜+127-127〜+127-128〜+127
加算で引き算できない補正が必要そのまま可能
現在の利用使われないほぼ使われない標準

「1の補数と2の補数の違い」は、「2の補数 = 1の補数 + 1」と覚えると整理しやすいです。1の補数で止めると+0/-0の問題が残り、+1することでゼロが1つになり、加算補正も不要になります。

📌
なぜ負の方が1つ多い?(表現範囲)

-12810000000000000000+12701111111負の数: 128個正の数: 127個 + 0負の数が1つ多い!

8ビットの2の補数で表せる範囲は -128 〜 +127 です。「あれ、-128まで行けるのに+128はないの?」と思うかもしれません。これは0が正の側に含まれるためです。

8ビットで表せる値の総数は 2の8乗 = 256個です。これを正と負に振り分けると:
正の側:0, 1, 2, ... 127 の 128個(0を含む)
負の側:-1, -2, ... -128 の 128個
合計 128 + 128 = 256個。0が正の側に入っている分、正の最大値は128ではなく127になります。

ビット数ごとの範囲はこうなります:
4ビット:-8 〜 +7
8ビット:-128 〜 +127
16ビット:-32,768 〜 +32,767
32ビット:約-21億 〜 約+21億
一般公式は -2n-1 〜 +2n-1-1 です。上のツールのビット数を切り替えて確認してみてください。

📌
オーバーフローの検出

4ビットの場合(-8〜+7)3 + 4 = 7 (OK)5 + 4 = -7 !?0101 + 0100 = 1001正+正→負 はオーバーフローMSBへのキャリーinとキャリーoutが異なる → overflow

計算結果がその型で表せる範囲を超えてしまうことをオーバーフローと呼びます。日常に例えると、車のメーターが999,999kmの次に000,000kmに戻ってしまうのと同じ現象です。

4ビット(-8〜+7)で具体例を見てみましょう。
3 + 4 = 7:+7は範囲内なので正常に計算できる
5 + 4 = 9:+9は+7を超えている。ビット列で見ると 0101 + 0100 = 1001 = -7
正の数同士を足したのに結果が負の数になってしまいました。これがオーバーフローです。

オーバーフローが起きたかどうかは、簡単なルールで判定できます。
正 + 正 → 負になった:オーバーフロー
負 + 負 → 正になった:オーバーフロー
・正 + 負、負 + 正 → 絶対にオーバーフローしない(正と負を足すと結果は必ず間に収まる)

プログラミングで怖いのは、多くの言語(C、Javaなど)で整数のオーバーフローがエラーにならず、黙って間違った値を返すことです。127 + 1 が -128 になっても何の警告も出ません。大きな数を扱う可能性がある場合は、より大きな型(int → long)や多倍長整数(BigInteger)を使って対策します。

📌
符号付きと符号なしの違い

ビット列 (8bit)符号なし (unsigned)符号付き (signed)
0000000000
000001015+5
01111111127+127
10000000128-128
11111011251-5
11111111255-1

同じビット列でも、符号付きと符号なしで解釈が変わります。 例えば 11111011 は、 符号なしでは 251、符号付きでは -5 です。

上のツールの「符号なし解釈」欄で、同じビット列の符号なし/符号付きの値を比較できます。 プログラミングでは C/C++ のintunsigned intの違いがこれに対応します。 型を間違えると予期しない値になるので注意が必要です。

特に注意すべきは、符号付きと符号なしの値を混在させた比較です。 たとえばC言語で-1 < 1uは 直感的にはtrueですが、-1が符号なしに変換されて4294967295になるためfalseになります。 Javaでは符号なし整数型がないため問題は起きにくいですが、ビット演算を行う際には同様の注意が必要です。

練習問題

🎯
基本情報技術者 練習問題

Q1.8ビットの2の補数表現で「-5」を表すビット列はどれか。
A.11111010
B.11111011
C.10000101
D.10000100
Q2.8ビットの2の補数表現で表せる最小の値はどれか。
A.-127
B.-128
C.-255
D.-256
Q3.2の補数表現のビット列「11111111」(8ビット)を10進数に変換するといくつか。
A.255
B.-1
C.-127
D.0

関連コンテンツ