CASL IIで2の補数を求めるプログラムの全貌
アセンブリ言語の基礎から応用まで、詳細な解説と実践的なコード例
2の補数は、コンピュータ科学において負の数を表現するための重要な概念です。特にアセンブリ言語のような低レベルなプログラミングでは、この概念を理解し、適切に扱うことが不可欠となります。本記事では、基本情報技術者試験で用いられるアセンブリ言語であるCASL IIを用いて、2の補数を計算するプログラムの作成方法について、その理論から具体的なコード例、そして関連する概念までを網羅的に解説します。
プログラム作成のハイライト
- 2の補数計算の基本: 全ビット反転と1の加算という、2の補数を求めるための基本的なアルゴリズムをCASL IIで実装します。
- CASL IIの命令体系: 汎用レジスタの活用や、データ定義命令(DC, DS)と擬似命令(START, END)の役割を理解し、効率的なコードを作成します。
- 応用的な数値表現: 符号付き数値の表現範囲やオーバーフローの概念を理解することで、より堅牢なプログラム設計に役立てます。
2の補数とは? その計算原理
負の数を表現する標準的な方法
2の補数(Two's Complement)は、コンピュータ内部で負の整数を表現するために広く用いられる方式です。この方式は、加算器で正と負の数の両方を統一的に扱えるという大きな利点があります。正の数は通常の2進数表現と同じですが、負の数はある特別な規則に従って表現されます。
2の補数を求める基本的な計算方法は以下の通りです。
- 元の正の数の2進数表現を用意します。
- すべてのビットを反転させます(1を0に、0を1に)。これを1の補数(One's Complement)と呼びます。
- 1の補数に1を加算します。
例えば、16進数の-0001を2の補数で表すとFFFFとなります。これは、バイナリで考えると理解しやすくなります。
\[ \text{元の数: } 0001_{\text{16}} = 0000000000000001_{\text{2}} \]
\[ \text{ビット反転(1の補数): } 1111111111111110_{\text{2}} \]
\[ \text{1を加算: } 1111111111111110_{\text{2}} + 1_{\text{2}} = 1111111111111111_{\text{2}} \]
したがって、\(1111111111111111_{\text{2}}\) は \(FFFF_{\text{16}}\) となり、これが-1の2の補数表現となります。
CASL II プログラミングの基礎知識
COMET IIアーキテクチャとCASL II命令
CASL IIは、情報処理技術者試験で使われる仮想コンピュータCOMET IIのためのアセンブリ言語です。COMET IIは1語(データ単位)を16ビットとし、#0000から#FFFF(0から65535)までの値を表現できます。命令語は2語長で32ビット構成です。CASL IIプログラムは、命令行と注釈行から構成され、1命令は1命令行で記述されます。
CASL IIプログラムの構造は以下のようになります。
PROGRAM_NAME START ; プログラムの開始
; 実質的なプログラムの記述(LD命令、LAD命令など)
; ...
RET ; サブルーチンからの戻り、またはプログラムの終了
; データ定義(DS命令、DC命令など)
; ...
END ; プログラムの終了
主要な命令としては、START(プログラムの開始を定義)、END(プログラムの終了を定義)、DC(定数を定義)、DS(記憶領域を確保)、そしてレジスタ操作や算術演算を行う命令群があります。CPUには汎用レジスタ(GR0-GR7)、フラグレジスタ、プログラムレジスタ、スタックポインタなどのレジスタが搭載されています。
コンピュータの内部構造を思わせる回路基板
CASL IIによる2の補数計算プログラム
実践的なコード例とその解説
それでは、CASL IIで2の補数を求めるプログラムを実装してみましょう。ここでは、汎用レジスタGR1に格納された値の2の補数を計算し、GR0に格納するプログラムを例とします。
TWOS_COMPLEMENT_PROG START ; プログラム開始
; GR1に2の補数を求めたい値を設定 (例: 5の場合)
LAD GR1, 5 ; GR1に5をロード
; または、既存の値をGR1にロードする場合
; LD GR1, INPUT_VAL ; INPUT_VALからGR1に値をロード
XOR GR0, GR0 ; GR0をゼロで初期化 (結果格納用)
CPA GR1, #0000 ; GR1が0かどうかを比較
JZE RETURN_ZERO ; 0ならばそのまま終了 (0の補数は0)
; 1の補数を計算 (ビット反転)
; XOR GR1, #FFFF を使用して、16ビットすべてのビットを反転させる
; これは、数値とFFFFとの排他的論理和を取ることで実現できる
XOR GR1, #FFFF ; GR1のビットを反転 (1の補数)
; 2の補数を計算 (1を加算)
ADDA GR1, #0001 ; GR1に1を加算 (2の補数)
; 結果をGR0に格納
LD GR0, GR1 ; 計算結果をGR0にコピー
RET ; 処理を終了して戻る
RETURN_ZERO
LD GR0, #0000 ; GR1が0の場合、結果は0
RET
; データ領域 (必要に応じて定義)
INPUT_VAL DC 5 ; 入力値の例
RESULT DS 1 ; 結果を格納する領域
TWOS_COMPLEMENT_PROG END ; プログラム終了
プログラム解説
START/END: プログラムの開始と終了を示します。TWOS_COMPLEMENT_PROGはプログラムのラベルです。LAD GR1, 5: 汎用レジスタGR1に直接値5をロードします。これはLAD (Load Address) 命令で、即値やアドレスをレジスタにロードする際に使われます。XOR GR0, GR0: GR0とGR0の排他的論理和を取り、GR0を0で初期化します。これは、結果を格納するレジスタをクリアする一般的な手法です。CPA GR1, #0000/JZE RETURN_ZERO: GR1の値が0かどうかを比較し、もし0であれば、0の2の補数は0であるため、RETURN_ZEROラベルにジャンプして処理を終えます。XOR GR1, #FFFF: ここが2の補数計算の核心です。16ビットのレジスタであるGR1のすべてのビットを反転させるために、#FFFF(すべてのビットが1)との排他的論理和(XOR)を取ります。XORの性質上、A XOR 1 = NOT Aとなるため、これで1の補数が得られます。ADDA GR1, #0001: 1の補数が格納されているGR1に1を加算し、2の補数を完成させます。LD GR0, GR1: 最終的な2の補数の結果をGR1からGR0にコピーします。RET: プログラムの実行を終了し、呼び出し元に戻ります。
2の補数計算の注意点
2の補数表現では、表現できる数値の範囲が決まっています。例えば、16ビットでは\(-32768\)から\(+32767\)までを表現できます。オーバーフロー(桁あふれ)に注意が必要です。また、最も大きい負の数(例: \(-32768\))の2の補数は、同じ値になるという特殊なケースも存在します。
アセンブリ言語と2の補数の深い関係
なぜ2の補数が重要なのか
アセンブリ言語でプログラミングを行う際、2の補数の理解は不可欠です。これは、CPUが内部で負の数をどのように処理するかを直接的に反映しているためです。2の補数を用いることで、減算を加算として処理できるため、CPUの回路を単純化し、演算効率を高めることができます。
例えば、A - B という減算は、A + (-B) と同等に扱えます。ここで-BはBの2の補数表現です。
アセンブリ言語における2の補数理解の重要性レーダーチャート
上のレーダーチャートは、アセンブリ言語を扱う上で2の補数がいかに重要であるかを示しています。「負数表現」は最も直接的な関連性があり、次いで「演算効率」と「回路単純化」が続きます。これらは、CPU設計の根幹に関わる部分であり、アセンブリ言語プログラマが意識すべき点です。「デバッグ容易性」と「システム安定性」も、2の補数の適切な理解がコードの信頼性に寄与することを示唆しています。
アセンブリ言語学習の意義
アセンブリ言語を学ぶことは、コンピュータがどのように命令を実行し、データを処理するのかを深く理解する上で非常に有益です。CASL IIの学習は、特に基本情報技術者試験のプログラミング分野で役立つだけでなく、低レベルなシステムプログラミングの基礎固めにもなります。
アセンブリ言語と低レベルプログラミングの関連性を示す動画
この動画は、アセンブリ言語の重要性と、それがどのようにシステムの根幹に関わっているかを示唆しています。直接CASL IIの解説ではありませんが、アセンブリ言語がハードウェアと密接に連携し、低レベルでの制御を可能にすることの重要性を理解する上で参考になります。
CASL IIにおける数値とデータ表現
データ定義と記憶領域
CASL IIでは、プログラム内で使用する数値やデータを定義するために、DC(Define Constant)命令とDS(Define Storage)命令を使用します。
| 命令 | オペランド | 機能 | 例 | 説明 |
|---|---|---|---|---|
DC |
定数 | 指定された定数をメモリに配置 | DATA1 DC 123 |
DATA1というラベルに123という値を定義 |
DS |
数値(語数) | 指定された語数分の記憶領域を確保し、初期値は不定 | ANS DS 1 |
ANSというラベルで1語分の記憶領域を確保 |
START |
[ラベル] | プログラムの先頭を定義し、実行開始番地を指定(省略可) | PROG START |
PROGというラベルでプログラム開始 |
END |
[ラベル] | プログラムの終わりを定義 | END |
プログラム終了 |
これらの命令は「擬似命令」と呼ばれ、アセンブラ(アセンブリ言語を機械語に変換するプログラム)に対する指示であり、直接的な機械語命令ではありません。プログラムの実行開始番地はSTART命令に指定されたラベルが参照されます。省略された場合は、START命令の次の命令から実行が開始されます。
よくある質問(FAQ)
CASL IIで2の補数を求める際に、負の数の入力はどのように扱いますか?
CASL IIのプログラムでオーバーフローが発生した場合、どのように検出できますか?
JO(Jump on Overflow)命令などを用いてチェックし、適切なエラー処理や警告を行うことができます。
CASL IIで2の補数を使って減算を行う例を教えてください。
SUBA(Subtract)命令を使用するのが一般的です。しかし、2の補数の原理を理解するために減算を加算として表現することも可能です。例えば、「A - B」を計算したい場合、まずBの2の補数を求め、それをAに加算します。
SUB_EXAMPLE START
LD GR0, VALUE_A ; GR0にAの値 (例: 10)
LD GR1, VALUE_B ; GR1にBの値 (例: 3)
; Bの2の補数を求める
XOR GR1, #FFFF ; GR1のビットを反転 (1の補数)
ADDA GR1, #0001 ; GR1に1を加算 (2の補数)
; AにBの2の補数を加算
ADDA GR0, GR1 ; GR0 = A + (-B) = A - B
ST GR0, RESULT_SUB ; 結果を格納
RET
VALUE_A DC 10
VALUE_B DC 3
RESULT_SUB DS 1
SUB_EXAMPLE END
このように、SUBA命令を使わずとも2の補数によって減算を実現できます。
推奨される次のステップ
- CASL IIにおけるCOMET IIのレジスタ構成と役割
- CASL IIの入出力命令とファイル処理
- 基本情報技術者試験におけるCASL IIの過去問題解説
- アセンブリ言語でサブルーチンを実装する方法
参考文献
Last updated May 21, 2025