コンピュータの数値表現
概要[編集]
コンピュータにおける数値表現、もう少し具体的に言うと、コンピュータのCPU内部のレジスタや演算装置での数値の表現や、プログラミング言語での数値の表現や、OSでの数値の表現について解説する。 そもそもCPU内部のレジスタや演算器においては、数値は、たかだか8ビット〜128ビット程度の[注釈 1]、限られた個数の、固定長のビット列で表わされている。そうした物理的な制約下で表現されたものであるので、コンピュータで扱われる﹁数値﹂というのは、数学で扱う︵純粋に、概念的な︶﹁数﹂とはしばしば、性質が異なっているもの、しばしば﹁別もの﹂の性質を示す、と考えたほうがよい。[注釈 2][注釈 3]データ単位[編集]
コンピュータにおける数値表現は、以下に説明するビットを最小単位として、ビット列によってなされる。ビットは2通りの状態を持ち、ビット列は2の冪乗通りの状態を持つ。二進整数に対応づけられる。ただし、それをどのように扱うかはCPUの設計方法にもより、たとえば8ビットの0000000〜1111111を十進数の﹁0〜255﹂として扱うCPU設計法があり、それが一般的ではあるが、同じ8ビットを﹁-128〜0〜127﹂として扱う設計法もある。ビット[編集]
ビット(英: bit)の実体は、現代的なコンピュータでは電子的な切り替えスイッチであり、電圧のLow / Highである[注釈 4]。一つの電気的なスイッチの状態を抽象概念化したものがビットであるといえる。
2つの状態「0または1」「Off または On」「no または yes 」などと解釈できる。単一のビットは下表の2種類の状態のどちらかを必ず表す。コンピュータの論理回路である電子回路では、電位の高い (High) 低い (Low) を使うことも多いから、HとLという表現が使われることも多い。この対応は逆でもよく、その場合を負論理という。[注釈 5]
ビットの状態 | 対応する数 |
---|---|
L | 0 |
H | 1 |
単一のビットでは2種類の値しか表せないが、2ビット、3ビットとビットを増やすことで倍々に組合せの数を増やせる(2ビットで4通り、3ビットで8通り)。
ビットの状態 | 二進表示 | 対応する数 |
---|---|---|
LL | 00 | 0 |
LH | 01 | 1 |
HL | 10 | 2 |
HH | 11 | 3 |
一般に b 個のビットが取れる状態の個数 N は N = 2b である。
ビット数 b | ビット列の状態の個数 N |
---|---|
1 | 2 |
2 | 4 |
3 | 8 |
4 | 16 |
5 | 32 |
6 | 64 |
7 | 128 |
8 | 256 |
バイト[編集]
バイト(英: byte)はコンピュータ上で1つの文字を表す単位で、その長さは文字コード表の大きさに依存するが、典型的には8ビットのビット列を指す。コンピュータ上で計算処理を行う際のデータ単位としてワードがある。1ワードに相当するビット列の長さはコンピュータ・アーキテクチャに依存して、バイトの倍数で表せる長さが選ばれる。1バイトが8ビットのコンピュータであれば、1ワードは従って8の倍数(特に2の冪)個のビットに相当する。
オクテット・ニブル[編集]
オクテット(英: octet)は8個のビットからなるデータ単位である。多くのコンピュータにおいて1バイトは8ビットであり、従ってバイトとオクテットは同義語となる。 しかしコンピュータネットワークの分野ではアーキテクチャに依存しないデータ単位が必要となるため、オクテットのような単位が主に使われ、(特定のアーキテクチャでは同義語であっても)バイトとは区別される。
ニブル(英: nibble)は4個のビットからなるデータ単位である。従って、オクテットの半分がニブルであり、1オクテットは2ニブルである。ニブルは16通りの状態を表わせる。0 から 15 の整数との対応例を表に示す。
ニブルの二進表現 | 対応する数 | ニブルの二進表現 | 対応する数 | |
---|---|---|---|---|
0000 | 0 | 1000 | 8 | |
0001 | 1 | 1001 | 9 | |
0010 | 2 | 1010 | 10 | |
0011 | 3 | 1011 | 11 | |
0100 | 4 | 1100 | 12 | |
0101 | 5 | 1101 | 13 | |
0110 | 6 | 1110 | 14 | |
0111 | 7 | 1111 | 15 |
なぜ二進法なのか?[編集]
●3値以上の値を識別するハードウェアは2値のハードウェアよりも複雑になる。 ●二進法は十進法よりもかなり効率がよい。初期のコンピュータは十進︵二進化十進表現︶を使っているものも多かった。しかし、電気回路のオンオフをそのまま利用できる二進法のほうが圧倒的に効率が良い。近年では、10ビット︵二進法では 0〜1023 の1024通りが表現可能︶を使って 0〜999 の1000通りを表現する、効率の良い Densely packed decimal といったものも考案されている。なお、初期のコンピュータ、特にリレー式の場合、入出力機器と比べ本体がたいして速くないため、入出力を十進でおこなうのであれば、二進←→十進の変換はそれなりに計算量が必要なので、むしろそのまま十進で扱ってしまったほうが効率が良いという場合もあった。なお﹁二進に比べて回路量が増え、信頼性が低くなるためである﹂といった説明が一般的だが、回路の冗長さを利用してエラーを検出する手法を併用し信頼性を上げているものがある。例えば、最初期のFACOMなどが挙げられる。一方で信頼性が低下する根拠としては、回路の持つインピーダンスによる電圧降下や電源や周辺回路によるノイズなどによって、本来の電圧が予定外の数値を表す電圧に変化してしまうことによる。 ●かつては、十以外の底を採用しようとした例もあったが、あまりうまく行かなかった。かつて、﹁三進法を使ったコンピュータは二進法よりも効率がよいのではないか?﹂と期待する人が一部におり、実験的に開発されたことがあった。﹁一般に数値を記号で表現するとき、三進法が最も効率がよいとされるが、二進法もそれとほぼ同程度の効率だ﹂などと考えた人がいたのである。だが、この効率に関する計算は、n状態の表現にはn個の素子が必要という仮定に問題があり、現実的には二進法を1素子の2状態で表現するのが圧倒的に有利である。三進法#経済性の記述も参照[1]。八進と十六進[編集]
八進法と十六進法は二進法の3桁と4桁に直接対応するので、コンピュータ関連の数を表現するためなどによく使われている。たとえば、整数値を二進法で 1001001101010001 などと表示しても、ぱっとその値を把握することはできない。なので、八進法や十六進法がよく使われる。 十進の体系では、10種類の数字︵0 から9︶を組み合わせて数値を以下のように表す。 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ... 八進の場合、8種類の数字を使う︵0 から7︶。 0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 ... すなわち、八進の "10" は十進の "8" に等しく、八進の "20" は十進の "16" に等しい。 十六進では、16種類の数字を使う︵0 から9の後に一般にAからFまでが続く︶。 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B... すなわち、十六進の "10" は十進の "16" に等しく、十六進の "20" は十進の "32" に等しい。底変換[編集]
これらはいずれも位取り記数法だが、十進法の桁の重み付けが10のべき乗であるのに対して、八進法では8のべき乗、十六進法では16のべき乗になっている。十六進や八進による表現から整数値を得るには、十進や二進などの他の記法の場合と全く同様に、各桁の数字にその桁位置の重み付け値をかけ、それらの総和を求めればよい。例えば、 八進 756 = (7 ×82) + (5 ×81) + (6 ×80) = (7 ×64) + (5 ×8) + (6 ×1) = 448 + 40 + 6 = 十進 494 十六進 3b2 = (3 ×162) + (11 ×161) + (2 ×160) = (3 × 256) + (11 ×16) + (2 ×1) = 768 + 176 + 2 = 十進 946 また、八進法の1桁は二進法の3桁にそのまま対応する。 000 = 八進 0
001 = 八進 1
010 = 八進 2
011 = 八進 3
100 = 八進 4
101 = 八進 5
110 = 八進 6
111 = 八進7
同様に、十六進法の1桁は二進法の4桁にそのまま対応する。
0000 = 十六進 0 1000 = 十六進 8
0001 = 十六進 1 1001 = 十六進 9
0010 = 十六進 2 1010 = 十六進 a
0011 = 十六進 3 1011 = 十六進 b
0100 = 十六進 4 1100 = 十六進 c
0101 = 十六進 5 1101 = 十六進 d
0110 = 十六進 6 1110 = 十六進 e
0111 = 十六進 7 1111 = 十六進f
そのため、二進による表現は、1001001101010001 のように長くても、単に数桁毎に区切って、そのまま書き換えるだけで、八進や十六進による表現に、書き換えできる。
001 001 001 101 010 001 二進 = 1 1 1 5 2 1 111521 八進
1001 0011 0101 0001 二進 = 9 3 5 1 9351 十六進しかし、十進には、これらのような単純な書き換えで変換することはできず、整数値を経由して普通に変換することになる。
符号付数値表現[編集]
符号付きの数値の表現法はいくつか存在する。必ずしも「符号ビット」があるとは限らない。例えば、ゲタ履き表現では、ゲタの値によっては「符号ビット」としては扱えない。符号ビットがある場合は、最上位ビットが符号ビットのことが多い。なお、符号ビットについて「1なら負の数を表し、0なら正の数を表す」といったように考えるのが自然なのは「符号と絶対値」表現の場合だけであり、たとえば「2の補数」表現であれば、最上位ビットは −(2N) の重みを持つ桁である、と解するのが自然である。
符号と絶対値[編集]
「符号と絶対値」表現は、1ビットの符号ビットと、絶対値を表す残りのビット群からなる。例えば、4ビットの場合で、MSBの、0が正、1が負を示すものとすると、
0101 = +5 1101 = −5
となる。浮動小数点数はたいていがこのような形をしている。ただし、絶対値の部分が指数部と仮数部に分かれている。
1の補数[編集]
1の補数とは、数のビット毎の反転が符号を反転させるとする表現である。これはビット単位のNOT演算に他ならない。例えば、
0101 = +5 1010 = −5
1の補数でも符号-仮数部表現でも、ゼロの表現が二種類存在するという問題がある。このため、どちらも最近のコンピュータでは滅多に使われない。1の補数では、
0000 = +0 1111 = −0
符号-仮数では、
0000 = +0 1000 = −0
2の補数[編集]
0101 = +5 1011 = −5したがって、
0000 = 十進 0 1000 = 十進 −8 0001 = 十進 1 1001 = 十進 −7 0010 = 十進 2 1010 = 十進 −6 0011 = 十進 3 1011 = 十進 −5 0100 = 十進 4 1100 = 十進 −4 0101 = 十進 5 1101 = 十進 −3 0110 = 十進 6 1110 = 十進 −2 0111 = 十進 7 1111 = 十進 −1この方式では整数であれば、16ビットで −32768 から 32767 の範囲、32ビットでは −2147483648 から 2147483647 の範囲を表現する。 2の補数の利点は、加減算かつオーバーフローを考えない範囲に結果が収まるような範囲に限定すれば、符号を気にせず符号無しの整数と同様に扱える点である。 例えば、5 + (−5) は以下のようになる。
0101 +1011 10000ここで、数値は4ビットで表しているので、演算結果も4ビットでなければならず、したがって先頭の1は捨てられ、結果として期待した通りの0が得られる。 演算において符号を気にする必要がないのは、2n を法とした合同式になっているためである。例えば、15 ≡ −1 (mod 16) である。コンピュータは一般に固定のビット数で数値を表すので、法が一定であり理想的である。2の補数表現と符号なし表現の違いは、大小比較方法と表示方法である。 [注釈 8]
小数の表現[編集]
固定小数点数[編集]
整数ビット群 小数ビット群 0.5 = 1/2 = 00000000 00000000.10000000 00000000 1.25 = 5/4 = 00000000 00000001.01000000 00000000 7.375 = 21/8 = 00000000 00000111.01100000 00000000ただし、この形式では二進では表せない数が出てくる。例えば、1/5︵十進では 0.2︶は正確に表すことはできず、最も近い値は以下のようになる。
13107/65536 = 00000000 00000000.00110011 00110011 = 0.1999969... 十進の場合 13108/65536 = 00000000 00000000.00110011 00110100 = 0.2000122... 十進の場合これは、桁を増やしても正確に表すことはできない。1/3 という数値を考えてみよう。これを十進の小数で表すと 0.333333... となって永遠に続く。これを適当な桁で止めると、その数値表現は 1/3 を正確に表すことはできていない。 つまり、十進で有限小数で表せる数が二進で有限小数になるとは限らない。これを回避する方法として、小数ではなく分子と分母を別々に格納した一種の分数として内部で保持する方式がある。しかし、平方根を求めるなどといった演算はできない。また、分数同士の加減算では通分によって分母が表現できないほど大きな値になる可能性があるため、﹁有理数型﹂というデータ型として、分母分子ともに多倍長整数で表すことが普通である。
浮動小数点表現[編集]
最大 | 最小 | |
---|---|---|
正の数 | 1.797693134862231E+308 | 4.940656458412465E-324 |
負の数 | -4.940656458412465E-324 | -1.797693134862231E+308 |
プログラミング言語における数値表現[編集]
低水準言語では、符号の有無や固定小数点か浮動小数点かを気にする必要がある。例えば浮動小数点の加算なのか整数の加算なのかによって、使用する命令が全く違ったものとなる。 LISPやPythonといった高水準言語では数値のデータ型はより抽象的であり、rational、bignum、complex などがある。それらの言語では、低水準言語と比べ、より抽象化され扱いやすいものとしてそれらの値が提供される。しかし﹁どんな数値であっても算術演算を正しく処理することができるはず﹂というのはただの幻想にすぎない。 コンピュータでは真の実数を扱うことはできないのだから、これらのデータ型でも同様に、それぞれの性質に注意して扱わねばならないことに違いは無い。演算子オーバーロードなどによって、符号無し整数、符号付整数、浮動小数点数、複素数など、複数のデータ型に対して、同じ見た目の式になるような言語もある。誤差[編集]
特に浮動小数点方式で演算する場合は誤差が生じるということには注意を払う必要があり、数値が表現可能な数値範囲を超えてしまう可能性にも十分に用心する必要がある[3][注釈 9]。分かりやすい出来事を紹介すると、たとえば1991年、アメリカ軍のパトリオットミサイルは時間計算の誤差が原因で誤作動して死者が出てしまったし[3]、欧州宇宙機構のアリアン5型ロケットなどは1996年の打ち上げ時にわずか40秒で爆発し、このロケットのために費やした10年の歳月および70億ドルの開発費および搭載した5億ドル相当の装置が失われてしまった[3]。アリアン5型の爆発の直接の原因は、慣性基準装置︵IRS︶のソフトウェアが水平方向の速度を表現する64ビット浮動小数点数を16ビット整数に変換したため、16ビット整数の最大値である32768を越えてしまい変換に失敗したことであった[3]。 特に浮動小数点方式で非常に近い2つの実数の引き算を行うと、有効桁がひどく損なわれて非常に大きい誤差が発生することがある[4]。たとえば32ビット(単精度)の状態で2つの近い実数の引き算をさせると、数学的に正しい値とは約20%も計算値がズレることがある[4]。脚注[編集]
注釈[編集]
出典[編集]
関連項目[編集]
外部リンク[編集]
- この記事は、パブリックドメインを表明しているvectorsiteの記事をベースとして英語版Wikipediaで執筆されたものを翻訳したものです。