#05 バイナリデータ入門

負の数の表現——2の補数とマイナスの取り扱い

問題:0と1だけでマイナスをどう表す?

これまで学んできたビットとバイトは、すべて「0以上の整数(正の数)」を表すものでした。しかし現実の計算では、気温、残高、座標など、マイナスの値 が欠かせません。

コンピュータは0と1しか扱えません。では「-1」や「-100」をどうやって表現するのでしょうか?

いくつかのアイデアが考えられますが、現代のコンピュータはほぼすべて 2の補数(Two’s complement) という方式を採用しています。その理由も含めて、順を追って説明します。


アイデア1:符号ビットを使う

最もシンプルな発想は「最上位ビット(左端のビット)を符号のフラグにする」ことです。

0 で始まる → 正の数
1 で始まる → 負の数

例えば8ビットで:

0 0001010  → +10
1 0001010  → -10

この方式を 符号・絶対値表現 と言います。

しかしこの方法には問題があります。

問題1:ゼロが2種類できる

0 0000000  → +0
1 0000000  → -0

「+0」と「-0」は同じ値のはずなのに、2通りの表現ができてしまいます。

問題2:足し算の回路が複雑になる

符号を判断してから計算を切り替える必要があり、回路設計が難しくなります。


アイデア2:2の補数方式

現代のコンピュータが採用している方式が 2の補数(Two’s complement) です。

この方式では、前回学んだ「オーバーフローで0に戻る」性質をうまく利用します。

核となるアイデア:-1 は「足すと0になる数」

-1の定義は「1を足したらゼロになる数」です。

1 + (-1) = 0

8ビットの世界で「足すと 00000000(= 0)になる数」を探してみましょう。

  0 0 0 0 0 0 0 1  (= 1)
+ ? ? ? ? ? ? ? ?  (= -1 のビット表現)
------------------
  0 0 0 0 0 0 0 0  (= 0)← オーバーフローして0に戻る

計算すると:

  0 0 0 0 0 0 0 1
+ 1 1 1 1 1 1 1 1
------------------
1 0 0 0 0 0 0 0 0  ← 9ビット目があふれて 0 0 0 0 0 0 0 0

つまり 11111111 = -1 です!


2の補数の作り方

「ある数のマイナス」を求める手順はシンプルです。

手順1:全ビットを反転する(ビット反転 / NOT演算)

手順2:1を足す

例:-10(マイナス10)を求める

まず 10 を2進数で書きます:

10 = 0 0 0 0 1 0 1 0

ステップ1:ビットを全部反転する(0→1、1→0)

0 0 0 0 1 0 1 0

1 1 1 1 0 1 0 1

ステップ2:1を足す

  1 1 1 1 0 1 0 1
+ 0 0 0 0 0 0 0 1
------------------
  1 1 1 1 0 1 1 0

結果:11110110 = -10 の2の補数表現

確認してみましょう。10 + (-10) = 0 になるはず:

  0 0 0 0 1 0 1 0  (= 10)
+ 1 1 1 1 0 1 1 0  (= -10)
------------------
1 0 0 0 0 0 0 0 0  → あふれて 00000000 = 0 ✓

2の補数がなぜ便利なのか

2の補数の最大の利点は 「足し算の回路をそのまま使える」 ことです。

  • 符号付きの足し算も、符号なしの足し算も、同じ回路でOK
  • 「+と−を判別してから計算を分ける」必要がない
  • ハードウェアが単純で速くなる
例:5 + (-3) = 2 を2の補数で計算

-3 の2の補数表現:
  3 = 00000011
  反転 → 11111100
  +1  → 11111101   ← これが -3

  0 0 0 0 0 1 0 1  (= 5)
+ 1 1 1 1 1 1 0 1  (= -3)
------------------
1 0 0 0 0 0 1 0  → あふれを除くと 00000010 = 2 ✓

8ビット符号付き整数の範囲

2の補数方式を使うと、8ビットで表せる値の範囲は次のようになります。

最小値:10000000 = -128
   -1:11111111 = -1
    0:00000000 = 0
   +1:00000001 = +1
最大値:01111111 = +127
ビットパターン符号付き(signed)符号なし(unsigned)
0000000000
00000001+11
01111111+127127
10000000-128128
10000001-127129
11111110-2254
11111111-1255

同じビットパターンでも、符号付き(signed)として読むか、符号なし(unsigned)として読むか で全く異なる値になることがわかります。


signed と unsigned の違い

プログラミング言語では、整数型を宣言するとき「符号付き(signed)か符号なし(unsigned)か」を指定できることがあります。

符号なし整数(unsigned)

  • 0以上の正の整数だけを扱う
  • 8ビットなら 0〜255
  • メモリアドレス、色のRGB値など負にならない値に使う

符号付き整数(signed)

  • 負の数も扱える
  • 8ビットなら -128〜127
  • 温度、座標の差分、カウントダウンなど負になりうる値に使う
ビット数ごとの範囲(2の補数方式):

  8ビット signed:-128 〜 127
  8ビット unsigned:0 〜 255

 16ビット signed:-32,768 〜 32,767
 16ビット unsigned:0 〜 65,535

 32ビット signed:約 -21億 〜 +21億
 32ビット unsigned:0 〜 約 43億

 64ビット signed:約 -922京 〜 +922京
 64ビット unsigned:0 〜 約 1844京

具体的な値で確認する

-1 はなぜ 11111111 なのか

1 の2進数:00000001

ビット反転:11111110
   +1:    11111111

-1 = 11111111 ✓

確認:00000001 + 11111111
       = 100000000  → 8ビットに収まらず 00000000 = 0 ✓

-128 はなぜ 10000000 なのか

128 の2進数:10000000

ビット反転:01111111
   +1:    10000000  ← もとに戻った!

-128 = 10000000 ✓

この「反転して+1したらもとと同じになる」という現象が、-128 が 8ビット符号付き整数の最小値である理由です。-128 に対応する +128 は8ビット符号付きの範囲(-128〜127)に入らないため、対称ではありません。


まとめ

  • 符号ビットだけではゼロが2種類できるなどの問題がある
  • 2の補数方式:ビット反転して1を足すとマイナスの数が得られる
  • -1 = 11111111 は「足すと0になる(オーバーフローして0に戻る)」から
  • 2の補数の最大の利点:加算回路をそのまま使えてハードウェアが単純になる
  • 8ビット符号付き整数の範囲は -128〜127(符号なしは 0〜255)
  • 同じビットパターンでも signed / unsigned で解釈が異なる

これでシリーズ「バイナリデータ入門」の基礎編は完了です。ビットとバイトから始まり、2進数・16進数の表現、オーバーフロー、そして負の数の表現まで、コンピュータがデータを扱う根本的な仕組みを学びました。