14.2.1. 符号付き整数
まずは、最も基本的な数である整数をコンピュータ内で表現する方法について説明します。
符号無し整数の符号化 #
非負整数の符号化は、 2 進法をそのまま用います。 これを、次の符号付き整数の対比で 符号無し整数 と呼びます。 何バイト使うかで、表現できる範囲が決まります。 \(m\) ビットを用いると \(0\) から \(2^{m-1}\) の範囲の整数が表現可能です。たとえば 1バイト = 8 ビットなら、 \(0\) から \(255 = 2^8-1\) までの整数が表現できます。
bits | min | max |
---|---|---|
8 | 0 | 255 |
16 | 0 | 65535 |
32 | 0 | 4294967295 |
64 | 0 | 18446744073709551615 |
計算機で使う標準的なデータ長が、標準的な整数の表現になります。 これは CPU (中央演算装置) が 1 回の命令で効率的に扱える大きさから決まります。 現在のほとんどのPCでは 64bitです。 2000年頃は32bitが主流でした。現在でも組み込み機器などでは32bit以下も使われています。 これをワード (word) とも呼びます。
四則演算 #
数の四則演算は2進でも10進でも同じです。 加算の例を示します。
\[6_{(10)}+5_{(10)}=11_{(10)}\] \[0110_{(2)}+0011_{(2)}=1001_{(2)}\]
オーバーフロー #
演算結果が表現範囲を超えることを オーバーフロー (overflow) と呼びます。
\( m\)
ビットで表せる非負整数は \( 0\)
から \( 2^{m-1}\)
までです。
この範囲内の数同士であっても、演算結果が範囲を外れてしまうことがあります。たとえば \(m=4 \)
ビットの加算で、以下のように結果の表現に 5bit 必要になった場合、5bit目 (左端の1
) は無視されます。
\[1101_{(2)}+0101_{(2)}=10010_{(2)} \underbrace{= 0010_{(2)}=2_{(10)}}_{\text{overflow}}\]
オーバーフローが発生したときに、上記のように誤った結果で淡々と計算が進むか、例外処理が発生するかは環境や設定によります。
符号付き整数の符号化 #
正負どちらもとる整数を符号付き整数と呼びます。
負の整数も含めて符号化するにはどうすれば良いでしょうか?
通常は 補数表現と呼ばれる方法を用いて負の整数を表します。
日常生活では-1
のように-
(マイナス記号) を用いますが、2進符号化では0
,1
しか使えません。
\(m-1\)
ビットの 正の2進数に対する補数を「足すと \(2^m\)
になる数」と定義します。
\(m=4\)
の例を表の左2列に示します。どの行も、数と補数の和が 1000
であることを確認してください。数と補数は1:1に対応します。
数 | 補数 | 10進数 | 解釈 (10進) |
---|---|---|---|
001 | 111 | 1 | -1 |
010 | 110 | 2 | -2 |
011 | 101 | 3 | -3 |
\(\vdots\) | \(\vdots\) | \(\vdots\) | \(\vdots\) |
111 | 001 | 7 | -7 |
これを利用して \(m\) ビットの符号付き整数を、 \(m-1\) ビットの非負整数と、補数を利用した負の数で表します
- 最上位bitが0
- 非負の 2進数。
- 最上位bitが1
- 負の数 — 残りの \(m-1\) bitを非負整数と解釈し、それに \(-2^{m-1}\) を加えたもの。上記の表の「補数」のbit列に対する一番右の列と同じ。
\(m\) bitでの表現範囲は \([-2^{m-1}, 2^{m-1}-1]\) です。 負の数の範囲が1多い理由は -0 は表現せずにその分を負の方に割り当てたためです。
bits | min | max |
---|---|---|
8 | -128 | 127 |
16 | -32768 | 32767 |
32 | -2147483648 | 2147483647 |
64 | -9223372036854775808 | 9223372036854775807 |
範囲は十分?
補数表現の利点 #
補数表現の利点は、負の数を1大きくしたときに、対応する補数表現を整数としてみれば1大きくなっていることです。 これにより、符号付き整数も符号無し整数と同様に四則演算をできます。
たとえば \(-1+1=0\) という計算を 4 ビット符号付き整数で行うと、以下のように 符号無し整数として計算して overflow が発生した結果とまったく同じです。
\[\underbrace{1111_{(2)}}_{-1_{(10)}} +\underbrace{0001_{(2)}}_{1_{(10)}} = \underbrace{10000_{(2)} = 0000_{(2)}}_{\text{(overflow)}}\]この点はコンピュータの中で整数の計算を担うハードウェアの設計で有利になります。