整数の10進・2進・16進数の変換に関しては、「データの内部表現(数値)」を参照してください。
シフト演算、小数点以下の基数変換、補数、浮動小数点
正整数の10進、2進、16進表示と基数変換と関しては、「データの内部表現(数値)」で扱いました。
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)
になります。これは21倍したことになります。
同様に、左に2ビットシフトすれば、22=4倍になります。
右に1ビットシフトすると(左端には0を詰める)、
0000 1001 (8+1=9)
となり、2-1=1/2倍したことになります。
これを組み合わせることにより、
「元の数Aを左に1ビットした数に、Aを左に2ビットシフトした数を加える」
と、2A+4A=6A の計算をしたことになります。
上の2進数を右に4ビットシフトすると、
0001 0010
→0010 0000
また、右に2ビットシフトすると
0001 0010
→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 のような表記になります。
たとえば0.8125は,
0.8125=0.5 (=1/2 → 0.12)
+0.25 (=1/4 → 0.012)
+0.0635 (=1/16→ 0.00012)
ですから,0.1+0.01+0.0001=0.11012となります。
BCD(Binary Coded Decimal、2進化10進)コードとは、1バイトを上下の4ビットに区切り、0~9を2進数の4ビットで表すことにより、1バイトで2つの10進数を表すコードです。
BCDコードを用いて任意の桁数の10進数を表したものです。奇数桁の場合は先頭に0を加え、符号付きの場合は末尾に符号を付けます。
数値の桁数の大小により、バイト数を指定することができます。1語のバイト数を任意に設定できることを可変長数といいます。整数(2進数)や実数(浮動小数点数)のように1語のバイト数が固定な数を固定長数といいます。
プログラムで変数を定義するときに、小数点位置を指定することができます。
パック10進数の特徴は、大きな数を表現できること、除算以外の四則演算で誤差を生じないことです。そのため、取扱金額が大きな会計処理などに向いています。
1バイトで1桁の数字を表す数です。文字列でのコード体系とほぼ一致しています。大きな容量になりますが、人による入出力での表現と内部表現が一致していること、コードなど文字列データに計算処理をするときなどに便利です。
これらのデータ型は、汎用コンピュータ上でCOBOL言語やPL/I言語で記述した事務処理システムでは必須のものでした。ところがほとんどのオープン系言語では通常では対応していません。64ビット2進数などにしています。また、これらの型への対応も進んでいるようです。
整数型では,取扱える数値が限定されますし,非常に大きな数や小さい数を取扱うことができませんので,科学技術計算などでは困ります。また、通常の科学技術計算では、12.3 というとき、厳密に 12.3000000000 である必要はなく、12.3 に近い数値だということが多いのです。そのような数値を実数といい、実数を表現するには,浮動小数点型を用います。
整数 浮動小数点数
小数点 一般には整数値 小数点あり(実数)
値の精度 正確な値 近似値
大小範囲 比較的狭い 非常に広い
計算処理 簡単(高速) 複雑(低速) *注
例えば、-640を-1.25×29 のように、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×29 は-2.5×28 や-0.625×10 など、多様に表現できますが、仮数を1.Mのように整数部分を1になるように調整することを正規化といいます。そして、M(0.25)の部分を2進数にしたものを仮数部に入れます。正規化を行うのは、仮数部(23ビット)での有効桁数を大きくするためです。
また、0.001=1.024×2-10 のように、絶対値が小さい数では指数が負になります。それで、20のときE=127、21のときE=128、2-2のときE=125などとなるように、元の指数に127を加えたEを2進数にしたものを指数部(8ビット)に入れます。この操作をバイアスといいます。
すなわち、-1.25×29 を浮動小数点表示すると、次のようになります。
S E(指数部、8ビット) M(仮数部、23ビット)
1 010001000 0100 … 0000
(-) (9+127=136) (1.25-1=0.25)
解答
符号が0→正数
指数部=1000 01102=13410=127+7→27
仮数部=0010 0000 … 00002=2-3=0.125
これに整数部の1を加えて、1.125
答 1.125×27=140.625
これまでに、いりいろなところでこの用語を使ってきました。整理すると、次のようになります。
実数系では、上のように指数部が範囲を超えること、絶対値が非常に大か、非常に0に近いときに発生します。
整数系では、1語のバイト数よりも大になってはみ出してしまうオーバーフロー、左側へのシフト(割り算)で末尾のビットがはみ出してしまうアンダーフローがあります。
1語のバイト数を多くすることで、深刻なオーバーフローやアンダーフローの発生を抑えることができます。整数でも実数でも処理系により標準的なバイト数が決まっており、それを単精度といい、単精度の2倍のサイズを倍精度といいます。さらには特殊な用途では4倍精度をもつ処理系もあります。
倍精度の計算は、内部で単精度の計算を複雑に組み合わせて実現しているので、計算時間は長くなります。