Web教材一覧ハードウェアとソフトウェア

データの内部表現(数値・上級)

整数の10進・2進・16進数の変換に関しては、「データの内部表現(数値)」を参照してください。

キーワード

シフト演算、小数点以下の基数変換、補数、浮動小数点


整数

正整数の10進、2進、16進表示と基数変換と関しては、「データの内部表現(数値)」で扱いました。

2数の加算

2進数も16進数もいったん10進数に変換して計算し、その結果を元の進数に基数変換すればよいのですが、あえて直接計算することにします。

2進数の加算
     ④③②①
      110       4×1+2×1+1×0    6
   +)  11           2×1+1×1  +)3
    ─────                     ──
     1001   8×1+4×0+2×0+1×1    9

①:0+1→1
②:1+1→2になるが2進法では10→1繰り上がって0→0
③:1と繰り上がりの1→1+1→1繰り上がって0→0
④:繰り上がりの1→1

16進数の加算
     ③②①
      AB          16×10+1×11   171
   +) F2          16×15+1×2  +)242
    ────                      ────
     19D    256×1+16×9+13      413

①:B+2→11+2=13→D
②:A+F→10+15=25→16×1+9→19→1繰り上がって9→9
③:繰り上がりの1→1

オーバーフロー

「8ビットの2進数」のように、1語のビット数が固定しているときは、次のような計算の結果は9ビットになり、先頭の1は無視されて、結果は00000000になってします。このような現象をオーバーフローといいます。

           ⑧⑦⑥⑤④③②①
           11111111
         +)00000001
          ─────────
          100000000
   オーバーフロー ┘   ↓
           00000000

補数

補数の説明図

コンピュータでは,演算回路を簡素化するために,加算回路はあるのですが減算回路は持たず,A-Bの減算をA+(-B)として加算にするのです。では,(-B)をどのように表現するのでしょうか?
 話を簡単にするために,1語を8ビットとします。10進法の5は2進法では00000101になります。唐突ですがそれに11111011を加えると右上図のように結果は0になります。これから,2進数の11111011を10進数の-5であるとすればよいことになります。そのために,8ビット(1語)の先頭ビットが0ならば正数,1ならば負数であるというように決めるのです。このように決めた体系を2の補数表現といいます。00000101の補数は11111011であり,1111011の補数は00000101です。
 補数の求め方は簡単で右下図のように「0/1反転,+1」の操作を行えばよいのです。
 以下,[1語8ビットで2の補数体系の2進数]の例をいくつか示します。これから,この体系で表現できる値の範囲は,-128~0~127であることがわかります。
   00000000     0
   00000001     1
   01111111   127
   10000000  -128
   10000001  -127
   11111111    -1

練習問題:1バイト2の補数での2進数11110111→10進数

整数

ここでは説明のため8ビット(1バイト)を1語としていますが、これでは-128~127の範囲で非現実的です。通常の処理系では32ビット(4バイト)で2の補数形式の(符号のある)データを整数(int)の1語としています。
 10進数で10桁程度になるので、オーバーフローが発生することは稀ですが、巨大な値を扱うときは、long として64ビットにします。逆に小さなデータしか使わずデータ容量を減らしたいときは short として16ビットにします。

シフト演算

シフト演算とは、2進数の乗除算を高速にする演算方法です。シフト演算とは、2進数の計算を高速にする演算方法です。
シフト演算には、符号なしデータを対象とする論理シフトと、符号ありデータを対象にする算術シフトがあります。

論理シフト

先頭ビットは符号ビットではなく、他のビットと同じ扱いになります。
 例えば、8ビットの2進数
    0001 0010 (=16+2=18)
を左に1ビットシフトすると(右端には0を詰める)、
    0010 0100 (=32+4=36)
になります。これは2倍したことになります。
 同様に、左に2ビットシフトすれば、2=4倍になります。

右に1ビットシフトすると(左端には0を詰める)、
    0000 1001 (8+1=9)
となり、2-1=1/2倍したことになります。

これを組み合わせることにより、
  「元の数Aを左に1ビットした数に、Aを左に2ビットシフトした数を加える」
と、2A+4A=6A の計算をしたことになります。

上の2進数を右に4ビットシフトすると、
    000 0010
   →0010 0000
 また、右に2ビットシフトすると
    0001 00
   →0000 1000
となり、赤のビットが消えてしまい、正確な値になりません。
 これをオーバーフロー、アンダーフローといいます。

算術シフト

先頭のビットが符号ビットであるデータでのシフト計算です。

●右への2ビット算術シフト(4で割る)上段図
  符号ビットはそのまま。
  次の2ビットは符号ビットと同じ。
  残りのビットは元のビット列から埋めていく。
  元ビット列であふれたビットは捨てる。
符号ビットが正のとき(左上図)
  元データ 01001010 は10進で74
  捨てられるビット10(=2)を除外すれば、74-2=72
  シフト後の00010010は10進で18
  74/4=18の関係になっている。
符号ビットが負のとき(右上図)
  元データ 11001010 の補数は00110110=54
  捨てられるビット10を除外すると54+2=56
  シフト後の11110010の補数は00001110は10進で14
  -56/4=-14
●左への2ビット算術シフト(4倍にする)下段図
左シフトによりオーバーフローが生じるのは論理シフトと同様ですが、算術シフトでは先頭ビットが符号ビットになっているので、実質は7ビットになり、元データの符号ビット直後のシフト分のビット列がオーバーフローすることになります。
  符号ビットはそのまま。
  元ビット列の符号ビット直後のシフト分のビット列を捨てる。
  その後のビット列を結果のビット列に詰める。
  シフト後の右端の空いた部分を0で詰める。
符号ビットが正のとき(左下図)
  元ビット列の残った部分は01010=10
  シフト後のビット列は00101000=40
  10×4=40
符号ビットが負のとき(右下図)
  オーバーフローした部分を1に置き換えると11101010となる
  その補数は00010110=22
  シフト後の1010 1000の補数は01011000=88
  -22×4=-88

固定小数点数

固定小数点数とは、10進数での 12.3 のように小数点をもつデータのことです。2進法では 101.01 のような表記になります。

2進数→10進数:0.1101→0.812510
2進数→10進数(小数) 右のような表を作成すれば,簡単に計算できます。
練習問題:2進数0.0011→10進数
10進数→2進数:0.812510→0.1101
10進数→2進数(小数) 10進数から,0.5(=1/2),0.25(=1/4),0.125(=1/8),・・・,を負にならないように引いていき,0にすることができれば変換できます。

 たとえば0.8125は,
   0.8125=0.5    (=1/2 → 0.1
         +0.25   (=1/4 → 0.01
         +0.0635 (=1/16→ 0.0001
ですから,0.1+0.01+0.0001=0.1101となります。

しかし,これよりも次の手順(右図)のほうが簡単でしょう。
  1. 10進数を2倍する。整数部分を繰り上がり欄に書き,計算結果の整数部分を0にする。
  2. 整数部分を0にした計算結果を新しい10進数として計算結果が0になるまで,「1」を繰り返す。
  3. 計算結果が0になったら,右図のように上から下へ書き下したものが求める2進数である。
練習問題:10進数0.1875→2進数
〇注意:2進数にできない10進小数がある!
一般的には,上のように2進数に変換できる10進小数はむしろ稀なのです。たとえば10進数の0.1を2進数にしようとすると,
    0.110=0.00011001100110011・・・
のように循環小数になってしまいます。
 コンピュータでの1語のビット数は有限ですから,どこかで打ち切られてしまいます。これを丸め誤差といいますが,10進小数をコンピュータで取扱うときには,あくまでも近似値であり正確な値にはならないのです。
16進数→10進数:0.0816→1/3210
16進数の小数点数を10進数に変換するには、
  0.116=1/1610
  0.0116=1/1610=1/25610
  0.00116=1/1610=1/409610
    :
のように考えます。
  0.0816=8×0.0116=8/25610=1/3210
10進数→16進数:5/3210→0.2816
分母を16の累乗とする分数の和に分解します。
5/32= 4/32→2/16 →2×0.116 →0.216
     +1/32→8/256→8×0.0116→0.0816
    =0.2816
16進数と2進数の変換
16進数と2進数の変換は,10進数をなかがちにして変換することもできますが,2 =16であることを利用すると,たとえば
16進数と2進数の変換の例    11010111010
  =110×2+1011×2+1010
  =616×16+B16×16+A16
  =6BA16
とすることができます。
 また,小数点以下の数では,
   0.110101
  =0.11010100
  =1101×2-4+0100×2-8
  =D16×16-1+416×16-2
  =0.D416
となります。

 すなわち,2進数を16進数に変換するには,小数点を基準に4個ずつに区切り(右側で4個にならないときは0を入れる),その区切りごとに2進数を16進数にすればよいことがわかります。逆に,16進数を2進数に変換するには,16進数の各数を4桁の2進数にすればよいことになります。
練習問題:16進数6BA→8進数

BCDコード

BCD(Binary Coded Decimal、2進化10進)コードとは、1バイトを上下の4ビットに区切り、0~9を2進数の4ビットで表すことにより、1バイトで2つの10進数を表すコードです。

パック10進数

BCDコードを用いて任意の桁数の10進数を表したものです。奇数桁の場合は先頭に0を加え、符号付きの場合は末尾に符号を付けます。
 数値の桁数の大小により、バイト数を指定することができます。1語のバイト数を任意に設定できることを可変長数といいます。整数(2進数)や実数(浮動小数点数)のように1語のバイト数が固定な数を固定長数といいます。
 プログラムで変数を定義するときに、小数点位置を指定することができます。

パック10進数の特徴は、大きな数を表現できること、除算以外の四則演算で誤差を生じないことです。そのため、取扱金額が大きな会計処理などに向いています。

ゾーン10進数(アンパックBCD)

1バイトで1桁の数字を表す数です。文字列でのコード体系とほぼ一致しています。大きな容量になりますが、人による入出力での表現と内部表現が一致していること、コードなど文字列データに計算処理をするときなどに便利です。

これらのデータ型は、汎用コンピュータ上でCOBOL言語やPL/I言語で記述した事務処理システムでは必須のものでした。ところがほとんどのオープン系言語では通常では対応していません。64ビット2進数などにしています。また、これらの型への対応も進んでいるようです。

浮動小数点数(実数)

整数型では,取扱える数値が限定されますし,非常に大きな数や小さい数を取扱うことができませんので,科学技術計算などでは困ります。また、通常の科学技術計算では、12.3 というとき、厳密に 12.3000000000 である必要はなく、12.3 に近い数値だということが多いのです。そのような数値を実数といい、実数を表現するには,浮動小数点型を用います。

          整数      浮動小数点数
    小数点   一般には整数値 小数点あり(実数)
    値の精度  正確な値    近似値
    大小範囲  比較的狭い   非常に広い
    計算処理  簡単(高速)  複雑(低速)  *注

例えば、-640を-1.25×2 のように、s・f×reという形式で表現します。ここで、s(-)を符号、f(1.25)を仮数,r(2)を基数、e(9)を指数といいます。すなわち、「±仮数×基数指数」で表現します。基数は、コンピュータ内部では通常は2です(float) が10を用いる (decimal) こともあります。出力表示の際はdecimal形式に変換されます。

*注
整数演算では、二つの数を2進数に変換して計算し、その結果を10進数に変換するだけでよいのですが、実数計算では、後述のように、指数や仮数など複雑な処理が必要になるので、処理時間が非常に遅くなります。科学技術計算を主とするコンピュータでは、実数計算に特化した演算回路をハードウェアで組み込み高速化を図っています。

浮動小数点数型の表示
浮動小数点数の形式を表現できる範囲の図示

IEEE754(1語32ビット)では、浮動小数点数の表現方法を次のように規定しています。
 符号は、正のとき0負のとき1とします。
 -640は、-1.25×2 は-2.5×2 や-0.625×10 など、多様に表現できますが、仮数を1.Mのように整数部分を1になるように調整することを正規化といいます。そして、M(0.25)の部分を2進数にしたものを仮数部に入れます。正規化を行うのは、仮数部(23ビット)での有効桁数を大きくするためです。
 また、0.001=1.024×2-10 のように、絶対値が小さい数では指数が負になります。それで、2のときE=127、2のときE=128、2-2のときE=125などとなるように、元の指数に127を加えたEを2進数にしたものを指数部(8ビット)に入れます。この操作をバイアスといいます。
 すなわち、-1.25×2 を浮動小数点表示すると、次のようになります。
   S E(指数部、8ビット) M(仮数部、23ビット)
   1     010001000      0100 … 0000
  (-) (9+127=136)    (1.25-1=0.25)

例題
次のIEEE754の32ビットの浮動小数点型数は、10進数ではいくつになるか。
   符号 指数部(8ビット) 仮数部(23ビット)
    0    1000 0110    0010 0000 … 0000

解答
符号が0→正数
指数部=1000 01102=13410=127+7→2
仮数部=0010 0000 … 00002=2-3=0.125
これに整数部の1を加えて、1.125
答 1.125×2=140.625

浮動小数点数の有効桁数
10進数の小数点数は、2進数では循環小数になる場合があります。仮数部のビット数は有限ですから、切られてしまいます。それによる誤差を丸め誤差といいます。
 仮数部が23ビットであり、整数部の1ビットを加えると24ビットになります。224≒10 なので、10進数での有効桁数は7桁になります(2進表示の桁数Bと10進表示の桁数Dの間には、
   2=10 → D=B×log102 となります。log102≒0.3ですから、24桁の2進数は10進数では24×0.3≒7桁になります)。
 また、浮動小数点数の計算では、多様な誤差が発生し、有効桁数は小さくなります。高精度が求められる場合には、1語を64ビットとする倍精度浮動小数点型を用います。
 浮動小数点数による誤差については、誤差の種類で扱います。
 指数部での最大値は1111 11112=25510、最小値は0000 00002=010です。バイアスを戻すと129、-128です。すなわち、絶対値が2129 より大きいときはオーバーフロー、絶対値が2-128 より小さい(0を除く)ときはアンダーフローとなり表現できないのです。倍精度浮動小数点型では指数部のビット数が大きいので、さらに大きい数や小さい数が表現できます。

オーバーフローとアンダーフロー

これまでに、いりいろなところでこの用語を使ってきました。整理すると、次のようになります。
 実数系では、上のように指数部が範囲を超えること、絶対値が非常に大か、非常に0に近いときに発生します。
 整数系では、1語のバイト数よりも大になってはみ出してしまうオーバーフロー、左側へのシフト(割り算)で末尾のビットがはみ出してしまうアンダーフローがあります。

単精度・倍精度

1語のバイト数を多くすることで、深刻なオーバーフローやアンダーフローの発生を抑えることができます。整数でも実数でも処理系により標準的なバイト数が決まっており、それを単精度といい、単精度の2倍のサイズを倍精度といいます。さらには特殊な用途では4倍精度をもつ処理系もあります。
 倍精度の計算は、内部で単精度の計算を複雑に組み合わせて実現しているので、計算時間は長くなります。