02.S/370における数と文字の表現
メインフレームに限らずコンピューターのCPUは内部で2進数を使用して演算処理を行っていることはよく知られています。アセンブラー言語のプログラミングではCPUの機械命令を直接使用し、メモリーにも直接アクセスすることになります。COBOLやPL/Iなどのいわゆる高級言語と異なり、数や文字、データがCPUでどのように処理されメモリーにどのように格納されるのかが具体的にわかっている必要があります。そのために数や文字が内部でどのように表現されるかを理解することは大切です。
2進数と16進数
私たちは日常生活では10進数(decimal number)を使います。0から始まって1,2,3と続き7,8,9となったらそれ以上の数字がないので繰り上がって10となります。0?9までの10の数字で表現するため10進数と呼ばれます。ところがコンピューターのCPUは2進数(binary number)を使います。0から始まって1ですが次はそれ以上の数字がないので繰り上がって10となります。0と1の2つの数字で表現するため2進数と呼ばれます。0か1かの2つの状態でしかないので、電気信号のオン/オフに対応させてハードウェアとしての記憶素子に情報を蓄えることができます。この0か1かのいずれの状態によって記憶素子に蓄えられる情報を「ビット(bit)」と呼びます。0の状態がビット・オフ、1の状態がビット・オンとなります。CPUのような機械にとっては0か1かの2進数の方が自然なわけです。なおS/370アーキテクチャでは10進数も扱えますが、基本となる演算処理は内部で2進数に変換されて行われます。
CPUが2進数を使用しメモリーにもビットのON/OFFでデータが蓄えられるならば、例えば100と言う数値は2進数では1100100、379は101111011、1234は10011010010となりますがとても人間が扱える表現方法ではありません。それでもアセンブラー・プログラミングでは数の取り扱いや演算結果、命令動作の確認などでCPUが行うとおりにやってみる必要が生じます。そこでCPUにとっては自然だが人間にとってはやっかいな2進数を扱うために16進数(hexadecimal number)を用います。16進数は0から始まって1,2,3と続き7,8,9となったら次にA,B,C,D,E,Fと続きます。Fの次はそれ以上の数字がないので繰り上がって10となります。0?9、A?Fまでの16の数字で表現するため16進数と呼ばれます。AとかBは数字じゃなくて文字だろうと思うかも知れませんが、それは10進数で考えるからです。16進数ではA,B,C,D,E,Fは数字の1部だと割り切ってください。
16進数は2進数と密接な関係を持ちます。16は2の4乗なので4ビットで表現できます。したがって2進数を4ビットずつ区切れば簡単に16進数に変換できます。先ほど例示した100と言う数値は2進数では1100100なので16進数では64、379は2進数では101111011なので16進数では17B、1234は2進数では10011010010なので16進数では4D2となります。2進数←→10進数変換は計算が必要ですが、2進数←→16進数変換は対応表で簡単に変換できます。実際にプログラミングを始めればいちいち対応表など見なくても直感で変換できるようになります。
16進数字 | 対応する2進数 | 対応する10進数 |
---|---|---|
0 | 0000 | 0 |
1 | 0001 | 1 |
2 | 0010 | 2 |
3 | 0011 | 3 |
4 | 0100 | 4 |
5 | 0101 | 5 |
6 | 0110 | 6 |
7 | 0111 | 7 |
8 | 1000 | 8 |
9 | 1001 | 9 |
A | 1010 | 10 |
B | 1011 | 11 |
C | 1100 | 12 |
D | 1101 | 13 |
E | 1110 | 14 |
F | 1111 | 15 |
ビット操作やマスク値の設定など2進と16進の変換はアセンブラー・プログラミングでは常に必要となります。実際にはさほど長い桁数を変換することはなく、4桁の2進<->1桁の16進に、8桁の2進<->2桁の16進に変換する程度です。なお2進数と10進数の変換計算については、その計算を行うプログラムでも作らない限り必要となることはありません。16進数と10進数も変換には計算が必要でデバッグ作業ではしばしば必要になりますが、n進数計算機能を持つ関数電卓を使えば簡単です。
バイトとワード
メモリーにはデータがビット単位に記憶されます。しかし私たちは1ビット、2ビットと言った長さの数を扱うことはほとんどありません。コンピューターではメモリーを複数の記憶素子をまとめて扱い、CPUがメモリーをアクセスする際の単位とします。S/370アーキテクチャーでは8ビットを1つのグループにしてバイト(byte)を構成します。メモリーはバイト単位にアクセスされるためメモリーアドレスもバイト単位に振られます。本来は1byte=8bitと決まっているわけではありません。初期のコンピューターでは7や9ビットなども使われました。S/360システムが1byte=8bitを採用したことや80年代以降Intel社の8bitや16bitのCPUが普及したので1byte=8bitが定着してしまいました。
S/370アーキテクチャーではバイトは4つにまとめられワード(語)を構成します。演算に使われる汎用レジスターも32bitで構成されています。さらに半分の長さのハーフワード(半語)、倍の長さのダブルワード(倍語)が使われます。そのためCPU命令ではバイト、ハーフワード、ワード(フルワード)、ダブルワードのいずれかの単位でメモリーアクセスすることができます。文字列をまとめて移動できる命令などもありますが、この場合でもバイト単位で合計○○○バイトのデータをメモリーに書き込む、と言った動作になりアクセスはバイト単位に行われます。
長さ | ビット数 | |
---|---|---|
バイト | 1バイト | 8ビット |
ハーフワード | 2バイト | 16ビット |
ワード | 4バイト | 32ビット |
ダブルワード | 8バイト | 64ビット |
数の表現(2進整数)
S/370アーキテクチャーでは整数は2進整数とも呼ばれ、符号を含んで16、32あるいは64ビットで表現されます。メーカーによってはマニュアルに2進固定小数点(Fixed Binary)と載っているものもありますが、実際には整数部のみが使われますので単なる整数と考えてかまいません。呼ばれ方の違いであってIBM、富士通、日立の各社アーキテクチャーに違いはありません。整数は多くのコンパイラー言語ではint型と呼ばれますが、メインフレームのアセンブラーでは integer と言う表現はあまり行われず、そのまま固定小数点とかバイナリーとか言われます。アセンブラー言語が規定した型名で呼ばれる場合もあります。(F型、H型など)
タイプ | 長さ | 表現できる数値 |
---|---|---|
ハーフワード(H) | 符号ビット+15ビット | -2^15?2^15-1 (-32,768?32,767) |
フルワード(F) | 符号ビット+31ビット | -2^31?2^31-1 (-2,147,483,648?2,147,483,647) |
ダブルワード(D) | 符号ビット+63ビット | -2^63?2^63-1 (長すぎるので省略) |
フルワード(4バイト)整数については1部の命令が符号無し32ビット整数として取り扱うこともできる。ダブルワード整数については乗算の積および除算の被除数としてのみ扱うことができる。一般にメインフレームの整数と言えばハーフワードまたはフルワードで考えればよい。C言語で言うshort(16ビット)とlong(32ビット)となる。int型でも32ビットで考えればよい。ちなみにCPUも32ビットCPUである。
符号付き32ビット整数ではマイナス値(負数)は2の補数で表現します。+1はx00000001、0はx00000000ですが、-1はxFFFFFFFFとなります。2の補数は簡単にできます。ビット補数を使えばいいのです。正の数を2進表現します。そしてすべての1を0に、0を1にひっくり返します。それに1を足せばよいのです。他の計算方法もありますがこれがいちばん簡単でしょう。
-37の場合: +37 = 00000000 00000000 00000000 00100101 11111111 11111111 11111111 11011010 ビットを逆にひっくり返す 11111111 11111111 11111111 11011011 最後の桁に1を足す -1の場合: +1 = 00000000 00000000 00000000 00000001 11111111 11111111 11111111 11111110 ビットを逆にひっくり返す 11111111 11111111 11111111 11111111 最後の桁に1を足す -2,147,483,647の場合: +2,147,483,647 = 01111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000 10000000 00000000 00000000 00000001
実際は自分で計算しなくても補数を取るCPU命令が使えます。ただ内部でこう表現されていることを知っているといろいろ便利なこともあります。
文字の表現(キャラクター)
S/370では文字はバイトで表現されます。1文字が1バイト(8bit)です。1バイトの2進数をどの文字に割り当てるかの対応を示すのが文字コードセットです。メインフレームではEBCDIC文字コードセットが使われ、数字文字0?9にはxF0?xF9が割り当てられます。ASCIIと異なり英文字は数字文字より小さなコード値(x81?xE9)が割り当てられます。文字をソートした時の並び順やゾーン10進数のゾーンビットのパターンが異なることは知っておく必要があります。
メモリー上のデータが数値(整数)なのか文字なのかは、そのデータを処理する命令によって決まります。演算命令を使えば整数と見なされますし、文字操作命令を使えば文字または文字列と見なされます。
x40 | x50 | x60 | x70 | x80 | x90 | xA0 | xB0 | xC0 | xD0 | xE0 | xF0 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 空白 | & | – | ソ | $ | 0 | ||||||
1 | 。 | ェ | / | ア | タ |  ̄ | A | J | 1 | |||
2 | 「 | ォ | イ | チ | ヘ | B | K | S | 2 | |||
3 | 」 | ャ | ウ | ツ | ホ | C | L | T | 3 | |||
4 | 、 | ュ | エ | テ | マ | D | M | U | 4 | |||
5 | ・ | ョ | オ | ト | ミ | E | N | V | 5 | |||
6 | ヲ | ッ | カ | ナ | ム | F | O | W | 6 | |||
7 | ァ | キ | ニ | メ | G | P | X | 7 | ||||
8 | ィ | ー | ク | ヌ | モ | H | Q | Y | 8 | |||
9 | ゥ | ケ | ネ | ヤ | I | R | Z | 9 | ||||
A | ? | ! | : | コ | ノ | ユ | レ | |||||
B | . | ¥ | , | # | ロ | |||||||
C | < | * | % | @ | サ | ヨ | ワ | |||||
D | ( | ) | _ | ’ | シ | ハ | ラ | ン | ||||
E | + | : | > | = | ス | ヒ | リ | ゛ | ||||
F | | | ? | ? | ” | セ | フ | ル | ゜ |
数の表現(パック10進数)
S/370では2進整数の他に10進数を扱うこともできます。命令で直接数値演算ができる形式がパック10進数、表示や印刷など人間が見てわかる文字形式に変換されたものがゾーン10進数(アンパック10進数)です。
バイト | バイト | バイト | バイト | ||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | C |
10進数で+123,456を示す例である。数値は4ビットずつに区切られ、0?9の値が入る。末尾の4ビットは符号で、+はC、-はDで示す。+はFでもかまわない。最大16バイト(31桁+符号)の長さを扱うことができる。
バイト | バイト | バイト | バイト | ||||
F | 1 | F | 2 | F | 3 | C | 4 |
10進数で+1,234を示す例である。数値は8ビットずつに区切られ、先頭4ビットにゾーンビット(xF)、後部4ビットに0?9の値が入る。末尾バイトの先頭4ビットは符号で、+はC、-はDで示す。+はFでもかまわない。パック10進数を演算した結果は命令でゾーン10進数に変換できるが符号はそのままCまたはDで設定される。末尾桁を表示する際にはプログラムで符号ビットを変換するなどして表示可能な文字列に編集する必要がある。
これから新たに事務計算用のプログラムをアセンブラーで作ることはないでしょうが、システム系プログラムでも2進整数の演算結果を人間がわかる形に編集してメッセージなどを組み立てて出力することはよくおこなわれます。このような時はパックやゾーン10進数がデータ変換のために使われます。
数の表現(浮動小数点)
符号 1bit | 指数部 7bit | 仮数部(小数部) 24 or 56 or 112bit |
仮数部の長さによって短精度、長精度、拡張精度の3種類があり、16進数でそれぞれ6,14,28桁となる。
S/370での浮動小数点は上図のように表現され、Excess-64方式とも呼ばれる16進浮動小数点です。符号は正負を表し0が+、1が-となります。仮数部は1以下の正の数を表し、小数点が仮数部の直前(ビット8の直前)にあるものとされます。指数部は16の累乗値を表し7ビットの2進数値から64を引いた値がべき数となります。この表現方法がExcess-64です。0?127の指数値は-64?+63のべき数に対応します。浮動小数点値は仮数部に、指数部で示すべき数を使った16のべき乗の値を、掛けたものです。仮数部 * 16^指数部で示すべき数、となります。ESA/390アーキテクチャーではさらに別の方式である2進浮動小数点(インテルCPUなどで使われている)と言うものもサポートされています。
これ以上はややこしいので解説しません。浮動小数点は2^31乗で示される±約21億4700万の整数演算では処理できない大きな数や小数点以下の値の演算が必要な科学技術計算などで使用されます。しかし百分率(%)や平均値などで計算結果を小数点表示(例えば1÷3を0.33と表示)したい場合などは整数演算して表示のしかただけ工夫したり、事務計算で大きな数を扱う場合はパック10進数を使うことも多く、システム系プログラムや事務処理系のアプリケーションで浮動小数点が使われることはほとんどありません。とりあえずは浮動小数点というものがあるんだ、とだけ知っておいて下さい。将来本当に必要になる機会が来たら調べてください。(ちなみに私は1度ぐらいしか使ったことがありません)