1.2. 数値の表現

1. 負の数

 負の数の表現方式には

  • 絶対値表現
  • 補数表現

の2種類があります。

1.1. 絶対値表現

 絶対値表現は、負の数を表す方法の一つです。この方法では、数の絶対値とその符号を別々に表します。

例えば、8ビットの数を考えてみましょう。

  1. 正の数の場合、最上位ビットは0で、残りの7ビットは数値の絶対値を表します。たとえば、\(+5\)10は、\(0000\) \(0101\)として表されます。
  2. 負の数の場合、最上位ビットは1で、残りの7ビットは数値の絶対値を表します。たとえば、\(-5\)10は、\(1000\) \(0101\)として表されます。

 この方法では、\(0\)10から\(127\)10までの128の異なる値を表すことができます。ただし、\(+0\)と\(-0\)の両方が存在し、それぞれ\(0000\) \(0000\)と\(1000\) \(0000\)として表されます。正と負それぞれ128なので合計256の数値表現ができます。

 絶対値表現の利点は、人間にとって直感的であることです。しかし、コンピュータのハードウェアで加算と減算を行う際に問題が発生します。たとえば、\(0000\) \(0101\) (\(+5\)10)と\(1000\) \(0101\) (\(-5\)10)を加算すると、\(1000\) \(1010\) (\(-10\)10)になってしまいます。これは期待される結果\(0000\) \(0000\) (\(0\)10)ではありません。符号をみながら計算しないといけません。そのため計算が複雑化することになります。

 このため、絶対値表現は、コンピュータの内部で数を表すためには通常使用されません。ただし、人間が読むことを目的とした場合、たとえば、ディスプレイに数値を表示する場合には、絶対値表現が使用されることがあります。

1.2. 補数表現

 補数表現は、コンピュータで負の数を表すための方法です。2の補数表現が最も一般的に使用されますが、1の補数表現も存在します。

  • 1の補数表現:
     1の補数表現では、数のビットを反転させることで、その数の補数を得ます。つまり、0を1に、1を0に変換します。たとえば、8ビットの数の場合、\(+5\)10は\(0000\) \(0101\)として表されます。\(-5\)10の1の補数は、それぞれのビットを反転させて\(1111\) \(1010\)となります。 1の補数表現の問題は、\(+0\)と\(-0\)の両方が存在し、それぞれ\(0000\) \(0000\)と\(1111\) \(1111\)として表されることとキャリーオーバーの課題があることです。(詳しくは「補数とは何か」参照)
  • 2の補数表現:
     2の補数表現では、数のビットを反転させてから、1を加えることで、その数の補数を得ます。たとえば、8ビットの数の場合、\(+5\)10は\(0000\) \(0101\)として表されます。\(-5\)10の2の補数は、\(1111\) \(1011\)です。 2の補数表現の利点は、加算と減算が通常のバイナリ加算と同じ方法で行えることです。これにより、ハードウェアが単純化されます。また、\(0\)は一意であり、\(+0\)と\(-0\)の区別はありません。

 2の補数表現は、現代のコンピュータで最も一般的に使用される方法です。

負の数値表現法(「プロセッサを支える技術」P031より引用)

2. 2の補数

 2の補数表現は、コンピュータで正数と負数を表すための最も一般的な方法です。この方法では、最上位ビット(最左のビット)が符号ビットとして使用され、そのビットが0の場合、数は正またはゼロであり、そのビットが1の場合、数は負です。

 ここでは、8ビットの数を例に取りますが、他のビット数でも同様です。

  1. 正の数とゼロ:
     正の数とゼロは、通常のバイナリ表現を使用して表されます。最上位ビットは0で、残りのビットは数値を表します。たとえば、\(+5\)10は、\(0000\) \(0101\)として表されます。
  2. 負の数:
     負の数は、その数の2の補数を取ることで表されます。2の補数を取るには、以下の手順を実行します。
    • 数のビットを反転させます。つまり、0を1に、1を0に変換します。
    • 1を加えます。
  3. 例:
     たとえば、-5の2の補数を取るには、以下の手順を実行します。
    • \(+5\)10のバイナリ表現は\(0000\) \(0101\)です。これを反転させると、\(1111\) \(1010\)になります。
    • \(1111\) \(1010\)に\(1\)を加えると、\(1111\) \(1011\)になります。
    • したがって、\(-5\)10は、\(1111\) \(1011\)として表されます。
-5の2の補数を取る

加算と減算:
 2の補数表現の利点の1つは、加算と減算が通常のバイナリ加算と同じ方法で行えることです。たとえば、\(+5\)10と\(-5\)10を加算すると、\(0000\) \(0101\) + \(1111\) \(1011\) = \(1\) \(0000\) \(0000\)となり、最上位の\(1\)は無視され、結果は\(0000\) \(0000\)(\(0\)10)になります。

範囲:
 8ビットの2の補数表現では、\(-128\)10から\(+127\)10までの整数を表すことができます。最小の数は\(1000\) \(0000\) (\(-128\)10)で、最大の数は\(0111\) \(1111\) (\(+127\)10)です。

オーバーフロー:
 オーバーフローは、結果が表現可能な範囲を超える場合に発生します。たとえば、8ビットの数の場合、\(+127\)10と\(+1\)10を加算すると、\(0111\) \(1111\) \(+\) \(0000\) \(0001\) \(=\) \(1000\) \(0000\)となり、これは\(-128\)10を表します。この場合、オーバーフローが発生します。

 2の補数表現は、現代のコンピュータで最も一般的に使用される方法です。

3. 浮動小数点

3.1. IEEE 754

 IEEE 754は、浮動小数点数の表現と計算のための国際標準です。この標準では、浮動小数点数は以下のように表されます。

  • 符号ビット(Sign bit):
     1ビット。0は正、1は負を示します。
  • 指数部(Exponent):
     指数部分を表すビット。指数は、バイアスされた形で格納されます。例えば、32ビットの浮動小数点数では、8ビットが指数部に使われ、バイアスは127です。つまり、実際の指数に127を加えた値が、指数部に格納されます。例えば、指数が+2の場合、この部分の値は129(= 2 + 127)となります。指数部のビットがすべて1の場合とすべて0の場合は特別な意味を持つことからこれを除外し(下記「異なる数値の表現」参照)、-126から+127までの指数を1から254のすべて正の数で表すことになります。これにより高速な計算が可能となります。
  • 仮数部(Mantissa or Significand):
     仮数部分を表すビット。正規化された数値の場合、最上位ビットは常に1なので、このビットは格納されず、残りのビットだけが仮数部に格納されます。

参考情報

また、英語での詳細な解説としては、以下も参考にできます:

3.2. 正規化

 正規化とは、浮動小数点数などの数値を一定の形式に整える作業のことです。
 たとえば、10進数でいうと「123.45」という数字は科学的記数法で「\(1.2345 × 10^{2}\)」と表せます。
 2進数の場合は、数値0.00101は、正規化されて\(1.01×2^{-1}\)となります。
 このように、数字を1以上10未満の部分(または2進数の場合は常に1以上2未満)と、桁数を表す指数に分けることで、一意で効率的な表現が可能になります。

 IEEE 754の浮動小数点数では、正規化(normalized)という方法が使われています。これは、ゼロ以外の数を必ず「1.xxx…」という形に変換する方法です。なぜなら、どんな数もこの形にすると最初の「1」は常に現れるため、実際には保存しなくても「暗黙の1」として利用でき、より多くの桁(精度)を表現できるからです。

3.3. 異なる数値の表現

 IEEE 754標準では、以下の4つの異なる数値表現が定義されています。

  1. 正規数(Normal numbers):
     これは、最も一般的な浮動小数点数の形です。仮数部は、正規化された数値(最上位ビットが1)を表します。
  2. ゼロ(Zero):
     全てのビットが0の場合、数値はゼロとして解釈されます。符号ビットだけが1で他が0の場合もゼロ(Zero)となり同様に取り扱われますが、特定の計算では正の0と負の0で意味がある場合もあります。
  3. 非正規数(Subnormal numbers):
     指数部が全て0で、仮数部が0でない場合、数値は非正規数として解釈されます。これは、非常に小さい数値を表現するために使われます。
  4. 無限大(Infinity)と非数(NaN):
     指数部が全て1の場合、数値は無限大または非数(NaN)として解釈されます。仮数部が全て0の場合、数値は無限大を表します。仮数部が0でない場合、数値は非数(NaN)を表します。

 32ビットの浮動小数点数は、以下のように構成されます。

  • 符号: 1ビット
  • 指数: 8ビット
  • 仮数: 23ビット

3.4. 単精度浮動小数点・倍精度浮動小数点

 単精度浮動小数点数と倍精度浮動小数点数は、コンピュータで実数を表現するための2つの異なる方法です。(IEEE754では、4倍精度浮動小数点まで標準化されています。)

  1. 単精度浮動小数点数 (Single-Precision Floating-Point):
    • 単精度浮動小数点数は、32ビット(4バイト)のメモリを使用して実数を表現します。
    • これらの32ビットは、符号ビット(1ビット)、指数部(8ビット)、および仮数部(23ビット)に分割されます。
    • 単精度浮動小数点数は、約7桁の十進数の精度を持っています。
  2. 倍精度浮動小数点数 (Double-Precision Floating-Point):
    • 倍精度浮動小数点数は、64ビット(8バイト)のメモリを使用して実数を表現します。
    • これらの64ビットは、符号ビット(1ビット)、指数部(11ビット)、および仮数部(52ビット)に分割されます。
    • 倍精度浮動小数点数は、約15桁の十進数の精度を持っています。

 これらの数値表現は、IEEE 754標準に従っています。この標準は、浮動小数点数の算術演算、表現、および丸めの方法を定義しています。

 倍精度浮動小数点数は、単精度浮動小数点数よりも高い精度が得られますが、その分メモリを多く消費し、計算に時間がかかる場合があります。そのため、アプリケーションの要件に応じて、適切な精度を選択することが重要です。

3.5. 単精度浮動小数点数の例

 例えば、32ビットの浮動小数点数で、\(-0.75\)10 を表現する場合、以下のようになります。

  1. 符号ビットは1(負)
  2. \(0.75\)10 を2進数で表すと \(0.11\)2 です。これを正規化すると、\(1.01×2^{-1}\)となります。
  3. 指数部は、\(-1 + 127 = 126\) で、2進数で \(0111\) \(1110\) です。
  4. 仮数部は、\(1.10\) の 下位2ビットの\(10\) です。これを23ビットに拡張すると、\(100\) \(0000\) \(0000\) \(0000\) \(0000\) \(0000\) です。

 したがって、\(-0.75\)10 は、\(1\) \(01111110\) \(10000000000000000000000\) として表されます。

4. BCD

 BCD(Binary-Coded Decimal)は、10進数の数字を2進数で表現する方法の一つです。

 32ビットのプロセッサでデータを処理する場合を考えてみます。

 BCDでは、1つの10進数の数字を4ビット(半バイト)で表現します。したがって、1バイト(8ビット)のメモリ空間には2つの10進数の数字を格納することができます。

 32ビットのプロセッサでは、通常、メモリ空間は32ビット(4バイト)単位でアクセスされます。したがって、32ビット(4バイト)のメモリ空間には、BCDで最大8つの10進数の数字を格納することができます。

 例えば、10進数の「\(12345678\)」は、32ビットのメモリ空間に以下のようにBCDで格納されます。

\(0001\) \(0010\) \(0011\) \(0100\) \(0101\) \(0110\) \(0111\) \(1000\)

 上記の例では、32ビット(4バイト)のメモリ空間に8つの10進数の数字がBCDで格納されています。

 BCDのメリットは、10進数と2進数の変換が容易で、人間にとって理解しやすいことです。デメリットは、メモリ効率が悪いことです。通常の2進数では4ビットで16種類の数を表現できますが、BCDでは10種類しか表現できません。

 BCDは、デジタルデバイス、マイクロコントローラ、金融関連のアプリケーションなどで使われます。

5. パック10進数

 パック10進数は、10進数の数字を効率的に格納するためのデータ形式です。

 32ビットのプロセッサでデータを処理する場合を考えてみます。

 パック10進数では、1バイト(8ビット)を2つの半バイト(4ビット)に分割し、それぞれの半バイトに0から9までの10進数の数字を格納します。ただし、最後の半バイトは、数値の符号(正または負)を表すために使われます。通常、C(1100)は正、D(1101)は負を表します。

 したがって、32ビット(4バイト)のメモリ空間には、パック10進数で最大7つの10進数の数字と1つの符号を格納することができます。

 例えば、10進数の「\(1234567\)」は、32ビットのメモリ空間に以下のようにパック10進数で格納されます。

\(0001\) \(0010\) \(0011\) \(0100\) \(0101\) \(0110\) \(0111\) \(1100\)

 上記の例では、32ビット(4バイト)のメモリ空間に7つの10進数の数字と1つの符号がパック10進数で格納されています。

 パック10進数のメリットは、メモリ効率が良く、10進数のデータを直接扱うことができるため、計算処理が高速になることです。デメリットは、通常の2進数と異なるため、特殊な処理が必要になることです。

 パック10進数は、金融関連のアプリケーション、データベース、COBOLプログラムなどでよく使われます。

6. ゾーン10進数

 ゾーン10進数(Zoned Decimal)は、コンピュータで文字と数値を一緒に扱うためのデータ形式です。ゾーン10進数は、EBCDIC(Extended Binary Coded Decimal Interchange Code)やASCII(American Standard Code for Information Interchange)などの文字コードを拡張して、数値データを表現します。

 ゾーン10進数では、1バイトを2つの部分に分割します。1バイトの上位4ビットを「ゾーン」と呼び、下位4ビットを「数字」と呼びます。ゾーンは通常、符号や特殊な意味を持たせるために使用されます。数字は、0から9までの10進数の数字を表現します。

 たとえば、EBCDICを使用したゾーン10進数では、10進数の「\(123\)」は、以下のように表現されます。

  • ‘1’は、EBCDICの’F1′
  • ‘2’は、EBCDICの’F2′
  • ‘3’は、EBCDICの’F3′

\(1111\) \(0001\) \(1111\) \(0010\) \(1111\) \(0011\)

 ゾーン10進数のメリットは、文字データと数値データを一緒に扱うことができるため、データの読み書きが容易になることです。デメリットは、メモリ効率が悪く、特殊な処理が必要になることです。

 ゾーン10進数は、COBOLプログラムや、レガシーシステム、データベースなどでよく使われます。

7. 参考情報

タイトルとURLをコピーしました