基本情報技術者 2019年 秋期 午後 問12
次のアセンブラプログラムの説明及びプログラムを読んで、設問1〜3に答えよ。
〔プログラム1の説明〕
符号が同一である二つの16ビットのパック10進数を加算する副プログラムADDP1である。本問では、パック10進数は、3桁の10進数の各桁をそれぞれ4ビットで表現し、最下位の4ビットに符号として、正又は0の場合は1100を、負の場合は1101を付与する数値表現とする。10進数246を、パック10進数で表現した例を、図1に示す。

符号が同一である二つのパック10進数の加算例を、図2に示す。

(1) 副プログラムADDP1は、加算の対象となる符号が同一である二つの16ビットのパック10進数が、GR1、GR2に設定されて、呼び出される。
(2) 副プログラムADDP1は、加算結果をGR0に設定して呼出し元に戻る。このとき、汎用レジスタGR1〜GR7の内容は元に戻す。ここで、加算において、10進数の百の位からの桁上がりは発生しないものとする。

設問1:
問題文を見る プログラム1中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:AND GR1,=#000F
イ:AND GR1,=#F000
ウ:AND GR1,=#FFFF
エ:OR GR1,=#000F
オ:OR GR1,=#F000
カ:OR GR1,=#FFFF
bに関する解答群
ア:JMI MERGE
イ:JNZ MERGE
ウ:JPL MERGE
エ:JOV MERGE
オ:JZE MERGE
cに関する解答群
ア:SLA GR1,0,GR3
イ:SLL GR1,0,GR3
ウ:SLL GR1,=4
エ:SRA GR1,0,GR3
オ:SRL GR1,0,GR3
カ:SRL GR1,=4
模範解答
a:ア、b:ア、c:イ
解説
解答の導き方
パック10進数は、10進数の各桁を4ビットずつで表す方法です。16ビットなら4個の4ビット部分に分かれ、図1の「246」は、左から百の位「2」、十の位「4」、一の位「6」、符号「C」で表されています。符号は一番右の4ビットです。
a:符号だけを取り出します。
プログラムでは、aの直後に「符号部を退避」としてGR1の値をRESULTに保存します。この時点のGR1は、加算対象のパック10進数です。符号だけを残すには、右端の4ビット以外を0にします。
ANDは、ビットごとに処理する命令です。GR1と「=#000F」のANDを取ると、右端の4ビットだけが残ります。したがって、aには「AND GR1,=#000F」が入り、解答群ではアです。
b:桁上がりがない場合は、桁上げ処理を飛ばします。
GR1とGR2から取り出した数字を加えた後、プログラムは「CPL GR1,=10」で10と比較します。10より小さい場合は、そのまま桁の値として使えます。10以上の場合は、10を引いて桁の値を1桁分に戻し、次の桁へ渡す桁上がりをGR0に設定します。
たとえば図2の一の位は、です。10を引いたを一の位の結果にし、桁上がりのを次の桁へ渡します。一の位の合計が10より小さい場合は、桁上げ処理を行わず、MERGEへ進めばよいので、bには「JMI MERGE」が入ります。解答群ではアです。
c:計算した桁を、結果の正しい位置に移します。
GR3は最初に4に設定され、その後、1桁処理するたびに4ずつ増えます。各桁は4ビットで表されるため、GR3の値に応じて、計算結果を次の位置へ移します。
SLL(論理左シフト:ビットを左へずらし、右側に空いた部分を0で埋める処理)なら、GR3の値だけGR1を左へずらせます。そこで、cには「SLL GR1,0,GR3」が入り、解答群ではイです。
固定値の4だけずらす「SLL GR1,=4」では、十の位や百の位を正しい位置に置けません。また、SLAは最上位ビットを変えずにシフトする命令です。百の位では、結果のビットが最上位ビットに届くことがあるため、この処理には適しません。
シフト後のGR1をRESULTとORで併合すると、退避しておいた符号や、それまでに求めた桁と組み合わせられます。図2の例では、一の位でからと桁上がりを求め、十の位でからと桁上がりを求め、百の位でを求めます。こうして、符号を保ったまま結果の各桁を組み立てます。
誤りやすいポイント
- 符号は一番右の4ビットです。aで「=#F000」を使うと、符号ではなく一番左の4ビットを取り出してしまいます。
- ANDは必要なビットだけを残す処理です。ORを使うと、不要なビットを0にできません。
- 10以上のときは、10を引いた値を現在の桁にし、桁上がりを次の桁に渡します。比較だけで桁上がりが完了するわけではありません。
- GR3は4、8、12と変化します。一の位から百の位まで同じ位置に置くのではないため、シフト量を固定値の4にはできません。
- 符号の「C」や「D」は、この表現で符号を示す値です。10進数の桁として加算するものではありません。
FAQ
Q:符号も加算する必要がありますか?
A:必要ありません。二つの数は符号が同一なので、片方から取り出した符号を結果に残し、数の各桁を加算します。
A:必要ありません。二つの数は符号が同一なので、片方から取り出した符号を結果に残し、数の各桁を加算します。
Q:なぜ最初に4ビット右へずらすのですか?
A:元のデータでは、一の位の右隣に符号があります。4ビット右へずらすと、一の位をGR1やGR2の右端に移して取り出せます。
A:元のデータでは、一の位の右隣に符号があります。4ビット右へずらすと、一の位をGR1やGR2の右端に移して取り出せます。
Q:百の位から桁上がりが発生した場合はどうなりますか?
A:この問題では、百の位からの桁上がりは発生しないものとしています。そのため、3桁の範囲内で結果を組み立てればよいという前提です。
A:この問題では、百の位からの桁上がりは発生しないものとしています。そのため、3桁の範囲内で結果を組み立てればよいという前提です。
関連キーワード: パック10進数、ビットマスク、論理シフト、桁上がり、符号表現
設問2:
問題文を見る 注記 本設問の空欄fは問題誤りのため、問12を選択した受験者全員を正解とする措置が取られている。
符号が異なる二つの16ビットのパック10進数を加算する副プログラムADDP2を作成した。プログラム2中のに入れる正しい答えを、解答群の中から選べ。ここで、プログラム2中のa、cには、設問1の正しい答えが入っているものとする。
〔プログラム2の説明〕
(1) 副プログラムADDP2は、加算の対象となる符号が異なる二つの16ビットのパック10進数が、GR1、GR2に設定されて、呼び出される。
(2) 副プログラムADDP2は、加算結果をGR0に設定して呼出し元に戻る。このとき、汎用レジスタGR1〜GR7の内容は元に戻す。

dに関する解答群
ア:JMI INI
イ:JNZ INI
ウ:JOV INI
エ:JPL INI
オ:JZE INI
eに関する解答群
ア:JMI MERGE
イ:JNZ MERGE
ウ:JOV MERGE
エ:JZE MERGE
オ:SLL GR1,0,GR3
カ:SRL GR1,0,GR3
fに関する解答群
ア:ADDA GR1,GR0
イ:ADDL GR1,=1
ウ:ADDL GR1,GR0
エ:ADDL GR3,GR0
オ:SUBL GR1,=1
カ:SUBL GR1,GR0
模範解答
d:エ、e:エ、f:正解なし
解説
解答の導き方
このプログラムでは、符号が異なる二つの数を加算します。符号が異なる場合は、数の大きさを比べて、小さい方を大きい方から引きます。たとえば、正の数と負の数の加算は、絶対値の差を求める処理になります。
パック10進数は、10進数の各桁を4ビットで表し、最後の4ビットで符号を表します。プログラムでは、GR1などのレジスタ(計算中の値を一時的に置く場所)を使って、各桁を順に取り出して計算します。
dについて
最初の「CPL GR1, GR2」は、GR1とGR2を比較する命令です。ここでは、数の大きさを比べて、大きい方をGR1に残したいところです。
比較の結果、GR1の方が大きければ、入れ替えずに「INI」へ進みます。GR1の方が小さい場合は、その後の命令でGR1とGR2を入れ替えます。したがって、「GR1の方が大きい場合にINIへ分岐する」命令を選びます。該当するのは「JPL INI」なので、dはエです。
なお、ここでの比較は、パック10進数全体を使った比較です。符号を表す部分は最下位の4ビットにあり、数の桁を表す部分はそれより上位にあります。そのため、異なる符号の数でも、大きさの異なる数なら数の桁の大小で比較できます。大きさが同じ場合にどちらをGR1に残しても、差は0になります。
eについて
各桁を引くときは、「SUBL GR1, GR2」で、GR1の桁からGR2の桁を引きます。ここで、引き算の結果が0なら、その桁の答えは0であり、次の桁への桁借りは必要ありません。
すでにある「JPL MERGE」は、引き算の結果が正の場合に「MERGE」へ進みます。しかし、結果が0の場合は分岐しません。そこで、空欄eでは、結果が0ならそのまま「MERGE」へ進む命令が必要です。該当するのは「JZE MERGE」なので、eはエです。
結果が負の場合は、桁借りが必要です。各桁は0から9なので、負の結果に10を加え、次の桁から1を借りる処理に進みます。「LAD GR0,1」でGR0を1にしているのは、その桁借りを記録するためです。
fについて
次の桁を計算するときには、直前の桁で発生した桁借りを反映する必要があります。たとえば、300から157を引く場合、1の位は0−7なので、答えは3で、10の位から1を借ります。続く10の位では、0−5だけでなく、その借りも含めて0−5−1を計算し、答えは4になります。
しかし、fの選択肢には、次の桁に対して正しい形で桁借りを伝える命令がありません。たとえば「SUBL GR1,GR0」は、GR1全体からGR0を引く命令です。GR1の下位4ビットが0のときに1を引くと、その部分は2進数の計算で15になります。次の桁の計算で15を使ってしまうため、10進数の桁借りとしては正しくありません。
このため、fには正しい選択肢がありません。設問の注記にも、fは問題誤りのため全員正解とする措置が取られたとあります。
最後に、計算結果の符号は、大きさの大きい方の数の符号を使います。また、結果が0の場合は、プログラム中の「CPL GR0, =#000D」以降で負の0を正の0に直します。
誤りやすいポイント
-
dで、符号が違うから符号だけを比べる
この処理では、先に二つの数の大きさを比べます。差を求めるため、大きい方をGR1に残す必要があります。 -
eで、引き算の結果が0のときも桁借りが必要だと考える
0−0のように結果が0なら、その桁の答えは0です。次の桁から借りる必要はありません。そのため、0の場合に「MERGE」へ進む分岐が必要です。 -
fで、2進数の1の引き算を10進数の桁借りと同じだと考える
パック10進数の各桁は4ビットで表されています。数全体から1を引くと、桁が0の場合は2進数の桁借りが起こります。これは、10進数の桁借りと同じ処理にはなりません。
FAQ
Q: なぜ符号が異なる数では、大きい方から小さい方を引くのですか?
A: 正の数と負の数の加算は、数直線上で反対方向へ進むことに相当します。そのため、絶対値の差を計算し、絶対値が大きい方の符号を結果に使います。
A: 正の数と負の数の加算は、数直線上で反対方向へ進むことに相当します。そのため、絶対値の差を計算し、絶対値が大きい方の符号を結果に使います。
Q: 「JPL」と「JZE」は、どのように使い分けますか?
A: このプログラムでは、「JPL」は比較結果が正のとき、「JZE」は比較結果が0のときに分岐します。引き算の結果が正の場合と0の場合を、それぞれ適切に処理するために使い分けています。
A: このプログラムでは、「JPL」は比較結果が正のとき、「JZE」は比較結果が0のときに分岐します。引き算の結果が正の場合と0の場合を、それぞれ適切に処理するために使い分けています。
Q: fの「SUBL GR1,GR0」は、なぜ正解にならないのですか?
A: GR1全体から1を引くと、下位の桁が0の場合、その桁は2進数の計算で15になります。次の処理は10進数の桁を取り出して計算するため、15を使うのは誤りです。桁借りを正しく伝える選択肢がないので、fは正解なしとなります。
A: GR1全体から1を引くと、下位の桁が0の場合、その桁は2進数の計算で15になります。次の処理は10進数の桁を取り出して計算するため、15を使うのは誤りです。桁借りを正しく伝える選択肢がないので、fは正解なしとなります。
関連キーワード: パック10進数、BCD(Binary-Coded Decimal:10進数の各桁を2進数で表す方式)、符号表現、条件分岐、桁借り、シフト演算
設問3:
問題文を見る 符号にかかわらず二つの16ビットのパック10進数を加算できるように、符号の組合せによって副プログラムADDP1とADDP2を使い分ける副プログラムADDPを作成した。プログラム3中のに入れる正しい答えを、解答群の中から選べ。
〔プログラム3の説明〕
(1) 副プログラムADDPは、加算の対象となる二つの16ビットのパック10進数が、GR1、GR2に設定されて、呼び出される。
(2) 副プログラムADDPの呼出し元に戻ったとき、加算結果はGR0に入っている。
gに関する解答群
ア:ADDL GR1,=1
イ:AND GR0,GR2
ウ:OR GR1,GR2
エ:SUBL GR1,=1
オ:XOR GR0,GR2
hに関する解答群
ア:JMI P2
イ:JNZ P2
ウ:JOV P2
エ:JPL P2
オ:JZE P2模範解答
g:オ、h:ウ
解説
解答の導き方
このプログラムは、2つのパック10進数の符号が同じならADDP1へ、異なるならADDP2へ分岐します。問題文では、ADDP1は「符号が同一である二つの16ビットのパック10進数」を加算すると説明されています。まず、符号が同じかどうかを調べる方法を考えます。
パック10進数の最後の4ビットは符号を表します。問題文では、正又は0の符号が1100、負の符号が1101です。この2つは、右端の1ビットだけが異なります。
gには、2つのビット列を比べるための排他的論理和を使います。排他的論理和は、対応するビットが異なるときだけ1になる演算です。GR0には最初にGR1の値がコピーされるので、GR0とGR2の排他的論理和を取れば、2つのパック10進数の各ビットの違いを調べられます。
符号の右端のビットに注目すると、次のようになります。
つまり、符号が同じなら右端のビットは0、異なるなら1です。したがって、gにはGR0とGR2の排他的論理和を取るXOR GR0,GR2が入ります。
次に、プログラムはSRL GR0,1でGR0を1ビット右へ論理シフトします。論理シフトは、ビット列を指定した方向へずらす処理です。このとき、元の右端のビットはオーバフローフラグに入ります。オーバフローフラグは、命令の処理で特定の条件が起きたかを示す記録です。ここでは、右端から出たビットが0か1かを確認できます。
この後に続く条件分岐では、JOVがオーバフローフラグが1の場合に分岐します。符号が異なると右端のビットが1なので、JOV P2によってP2へ進み、ADDP2を呼び出します。符号が同じなら右端のビットは0なので分岐せず、ADDP1を呼び出します。
したがって、hにはJOV P2が入ります。
誤りやすいポイント
- パック10進数の数字部分も含めて、2つの数値全体が同じかどうかを調べる問題ではありません。見るのは符号を表す部分です。
- XORの結果全体ではなく、符号の違いを表す右端のビットに注目します。数字部分に違いがあっても、符号の右端のビットで符号の違いを判定できます。
- JOVは、ここでは通常の加算による桁あふれを調べるために使っているのではありません。SRLで右端から出たビットがオーバフローフラグに入る仕組みを利用しています。
- 符号が異なる場合に分岐するので、JOVの分岐先がADDP1ではなくP2である点に注意してください。
FAQ
Q: なぜ符号の右端のビットだけで判定できるのですか?
A: 正又は0を表す1100と、負を表す1101は、右端のビットだけが異なるためです。2つの符号の排他的論理和を取ると、符号が同じなら右端は0、異なるなら右端は1になります。
A: 正又は0を表す1100と、負を表す1101は、右端のビットだけが異なるためです。2つの符号の排他的論理和を取ると、符号が同じなら右端は0、異なるなら右端は1になります。
Q: SRLの後にJOVを使うのはなぜですか?
A: SRLで右端から押し出されたビットがオーバフローフラグに入るからです。JOVは、そのフラグが1かどうかを使って分岐します。
A: SRLで右端から押し出されたビットがオーバフローフラグに入るからです。JOVは、そのフラグが1かどうかを使って分岐します。
Q: 符号が同じ場合は、プログラムのどこへ進みますか?
A: 符号が同じときはオーバフローフラグが0なのでJOVで分岐しません。そのままCALL ADDP1に進みます。
A: 符号が同じときはオーバフローフラグが0なのでJOVで分岐しません。そのままCALL ADDP1に進みます。
関連キーワード: パック10進数、排他的論理和、論理シフト、オーバフローフラグ、条件分岐



