1.2. 数値の表現

1. 概要

 コンピュータにおける数値の表現は、デジタル機器が数値データを正確に処理するための基盤となる重要な概念です。特に負の数と小数の表現方法は、計算精度や処理効率に直接影響するため、情報処理技術者にとって必須の知識となります。

 負の数の表現には符号と絶対値表現、1の補数表現、2の補数表現などがあり、現代のコンピュータでは主に2の補数表現が採用されています。小数の表現については、固定小数点表現と浮動小数点表現の2つの方式があり、それぞれ異なる特性と用途を持ちます。これらの表現方法を理解することで、プログラミングにおける数値計算の精度問題や、システム設計における適切なデータ型の選択が可能になります。

2. 負の数

 負の数の表現方式には

  • 絶対値表現
  • 補数表現

の2種類があります。

2.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)ではありません。符号をみながら計算しないといけません。そのため計算が複雑化することになります。

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

2.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より引用)

3. 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の補数表現は、現代のコンピュータで最も一般的に使用される方法です。

4. 浮動小数点

4.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なので、このビットは格納されず、残りのビットだけが仮数部に格納されます。

参考情報

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

4.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」として利用でき、より多くの桁(精度)を表現できるからです。

4.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ビット

4.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標準に従っています。この標準は、浮動小数点数の算術演算、表現、および丸めの方法を定義しています。

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

4.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\) として表されます。

5. 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は、デジタルデバイス、マイクロコントローラ、金融関連のアプリケーションなどで使われます。

6. パック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プログラムなどでよく使われます。

7. ゾーン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プログラムや、レガシーシステム、データベースなどでよく使われます。

8. 実例・実用場面

 数値表現の理論を理解することは重要ですが、それらがどのような場面で実際に活用されるかを把握することで、より実践的な知識となります。ここでは、各数値表現方式が実務のどのような場面で選択され、活用されているかを具体例とともに解説します。

8.1. 2の補数表現の実例

 2の補数表現は、現代のコンピュータにおける整数演算の基盤となっており、様々な分野で活用されています。

組み込みシステム開発

  • センサーの値(温度-40℃〜+85℃など)を8ビットや16ビットで効率的に処理
  • マイクロコントローラでのAD変換値の正負判定
  • モーター制御における回転方向の表現(正転/逆転)

画像処理

  • RGB値の差分計算で負の値が発生する場面での色差計算
  • エッジ検出フィルタでの勾配計算
  • ヒストグラム均等化における輝度値の調整

ゲーム開発

  • キャラクターの座標計算で負の座標を扱う場面
  • 2Dゲームでの画面外座標の管理
  • 物理演算での速度ベクトル(正負の方向性)

暗号化処理

  • 整数演算での桁あふれ検出とエラーハンドリング
  • 公開鍵暗号での大整数演算の前処理
  • ハッシュ関数での循環演算

8.2. 浮動小数点表現の実例

 浮動小数点表現は、広範囲の数値を扱う必要がある分野で重要な役割を果たしています。

科学計算

  • 物理シミュレーションでの極大・極小値の扱い(アボガドロ定数:6.022×10²³など)
  • 気象予測での大気圧変化の微細な計算
  • 分子動力学シミュレーションでの原子間距離計算

金融システム

  • 為替レート計算での精度管理(ただし最終的な金銭計算では注意が必要)
  • 金融工学でのオプション価格計算
  • リスク管理での統計計算

3Dグラフィックス

  • 座標変換や光線計算での高精度演算
  • 3Dモデルの頂点座標処理
  • レンダリングパイプラインでの行列演算

AI・機械学習

  • ニューラルネットワークの重み計算での数値安定性
  • 勾配降下法での微小な重み更新
  • 深層学習での活性化関数の計算

8.3. BCD・パック10進数の実例

 BCD・パック10進数は、10進数の厳密な表現が求められる分野で採用されています。

金融システム

  • 預金残高や取引金額の厳密な小数点計算
  • 利息計算での端数処理
  • 外国為替取引での正確な金額管理

POSシステム

  • 商品価格や税込み計算での端数処理
  • レシート印刷での正確な金額表示
  • 割引計算での丸め誤差回避

会計システム

  • 帳簿計算での丸め誤差回避
  • 減価償却計算での年次処理
  • 税務申告での正確な金額計算

レガシー業務システム

  • COBOLベースのシステムとの連携
  • メインフレームでの大量データ処理
  • 既存の業務システムとの互換性維持

8.4. 数値表現方式の選択フローチャート

以下のフローチャートは、用途に応じて適切な数値表現方式を選択するための指針を示しています。

flowchart TD
    A[数値データの用途] --> B{金銭計算?}
    B -->|YES| C[BCD/パック10進数
・丸め誤差なし
・厳密な小数点計算] B -->|NO| D{科学計算?} D -->|YES| E[IEEE754倍精度浮動小数点
・広範囲の数値
・高精度計算] D -->|NO| F{組み込みシステム?} F -->|YES| G[2の補数(最小ビット)
・メモリ効率重視
・高速処理] F -->|NO| H{リアルタイム処理?} H -->|YES| I[IEEE754単精度浮動小数点
・処理速度重視
・十分な精度] H -->|NO| J[2の補数/浮動小数点
・汎用的な用途] C --> K[例:銀行システム
会計ソフト] E --> L[例:物理シミュレーション
AI計算] G --> M[例:センサー制御
マイコン処理] I --> N[例:3Dゲーム
リアルタイム描画] J --> O[例:一般的な
アプリケーション]

8.5. システム別数値表現の使い分け

実際のシステム開発では、以下の表を参考にして適切な数値表現を選択することが重要です。

システム種別 主な数値表現 選択理由 具体例
金融システム パック10進数・BCD 丸め誤差の完全回避、厳密な小数点計算、法的要件への対応 預金残高:1,234,567円、利率計算:0.025%
組み込み制御 2の補数(16bit)・固定小数点 メモリ効率最優先、高速処理、リアルタイム性 温度センサー:-40〜+85℃、PWM制御値:0〜1023
科学計算 IEEE754倍精度・64bit浮動小数点 広範囲の数値表現、高精度計算、標準ライブラリ対応 アボガドロ定数:6.022×10²³、π:3.141592653589793
3Dゲーム IEEE754単精度・32bit浮動小数点 処理速度重視、GPU最適化、十分な精度 座標:(x,y,z)=(-12.5, 0, 45.8)、回転角:90.5度
レガシーシステム ゾーン10進数・EBCDIC形式 既存資産の活用、COBOLとの互換性、文字データとの混在 顧客番号:’001234567’、商品コード:’ABC123′

8.6. 精度による影響の実例

数値表現の違いが実際の計算結果に与える影響を、具体的な例で示します。

例:0.1を10回加算した場合の比較

BCD表現の場合

  • 結果:正確に1.0
  • 内部表現:1.0000000000000000
  • 特徴:丸め誤差が発生しない

IEEE754浮動小数点表現の場合

  • 結果:約0.9999999999999999
  • 内部表現:0.9999999999999998
  • 特徴:2進数では0.1を正確に表現できないため誤差が蓄積

この例からわかるように、金融計算では、このような微小な誤差が積み重なると重大な問題となるため、BCD系の表現が必須となります。

8.7. 処理速度と精度のトレードオフ

実用的なシステム設計では、処理速度と精度のバランスを考慮する必要があります。以下のマトリックスを参考に、要件に応じた最適な選択を行うことが重要です。

パフォーマンス・精度マトリックス

  • 高精度・低速領域:BCD・パック10進数(金融計算)
  • 高精度・高速領域:倍精度浮動小数点(科学計算)
  • 低精度・高速領域:2の補数(組み込みシステム)、単精度浮動小数点(ゲーム・CG)

8.8. 適切な表現方式の選択指針

数値表現方式を選択する際の基本的な指針は以下の通りです。

精度が最重要

  • 金融計算、会計処理 → BCD・パック10進数
  • 法的要件がある計算での丸め誤差の完全排除

処理速度重視

  • リアルタイム処理、ゲーム開発 → 2の補数・単精度浮動小数点
  • 高速な演算処理が求められる場面

メモリ効率重視

  • 組み込み機器、IoTデバイス → 用途に応じた最小ビット数選択
  • 限られたメモリ資源での効率的な数値表現

広範囲・高精度が必要

  • 科学計算、エンジニアリング → 倍精度浮動小数点
  • 極大値や極小値を扱う計算処理

これらの実例を理解することで、理論的な知識を実際のシステム開発に効果的に活用できるようになります。適切な数値表現の選択は、システムの性能、精度、保守性に直接影響するため、要件に応じた慎重な判断が必要です。

9. まとめ

 数値の表現方法は、コンピュータシステムの基礎となる重要な概念です。2の補数表現による負の数の表現は、効率的な算術演算を可能にし、現代のプロセッサの基盤となっています。浮動小数点表現は、広範囲の数値を扱うことができる一方で、精度の限界や丸め誤差に注意が必要です。

 情報技術者には、これらの表現方法の原理と変換方法、それぞれの特性と適用場面の理解が求められます。実際のシステム開発においても、適切な数値表現の選択は、性能と精度の両面で重要な影響を与えるため、確実な理解を身につけることが重要です。