基本情報技術者 2018年 秋期 午後 問08
次のプログラムの説明及びプログラムを読んで、設問1~3に答えよ。
整数式を受け取って、その値を返すプログラムである。例えば、例1に示す整数式を受け取ると、その値50を返す。
例1: 2×(34-(5+67)÷8)
〔プログラムの説明〕
(1) 整数式は、文字の列で与えられる。整数式は、次のもので構成される。
・符号のない数字0~9の並び
・演算子: +、-、×、÷
・括弧: (, )
(2) 引数Expression[]で整数式を、引数ExpLenで整数式の文字数を、それぞれ受け取る。
(3) プログラム中の破線で囲んだ解析処理の部分では、受け取った整数式を解析し、計算に必要な情報を配列及び変数に設定する。
(4) プログラム中の破線で囲んだ計算処理の部分では、(3)で設定した情報を用いて、整数式の値を計算する。整数式の値は、Value[0]に得られる。
(5) 各配列の添字は、0から始まる。各配列の要素数は、十分に大きいものとする。
(6) 受け取った整数式に誤りはないものとする。また、計算の過程で、あふれやゼロ除算は発生しないものとする。
〔プログラム〕


〔プログラム(解析処理の部分)の説明〕
(1) Expression[]で渡された整数式を解析し、計算に必要な情報を配列Operator[], Priority[], Value[]及び変数OpCntに設定する。関数int()は、引数の数字が表す値を整数型で返す。
(2) 例1の整数式について、プログラム(解析処理の部分)を実行した直後の各配列及び変数の状態を、図1に示す。


〔プログラム(計算処理の部分)の説明〕
(1) 整数式の値を計算していく。図1に示す各配列及び変数の状態から、プログラム(計算処理の部分)の最外側の繰返しを1回実行した直後の各配列及び変数の状態を、図2に示す。


設問1:
問題文を見る プログラム(解析処理の部分)に関する次の記述中のに入れる正しい答えを、解答群の中から選べ。
プログラム(解析処理の部分)の行①〜④で用いている定数について考察する。
まず、行③及び④の処理では、定数として10を用いているが、この定数は10である必要はない。このプログラムにおいては、定数がaであれば常に正しい演算順序が保証される。
また、行①及び②の処理では、定数として1及び2を用いているが、次に示すように書き換えることが可能である。ここで、priLow及びpriHighは整数の定数を表し、その値はpriLow < priHighとする。
①→ ・Priority[OpCnt] ← nest + priLow
②→ ・Priority[OpCnt] ← nest + priHigh
このように表現したとき、行③及び④の処理では、nestの値を増減する定数がbのときに限り正しい演算順序が保証されることになる。
aに関する解答群
ア:1以上
イ:2以上
ウ:11以下
エ:12以下
bに関する解答群
ア:priHigh以上
イ:priHigh + 1以上
ウ:priHigh − priLow以上
エ:priHigh − priLow + 1以上
模範解答
a:イ、b:エ
解説
解答の導き方
この設問では、括弧の内側を外側より先に計算するために、演算子(+や×など、計算の種類を示す記号)に付ける優先順位をどう設定すればよいかを考えます。
-
括弧の深さに応じて、優先順位が変わります。
解析処理では、括弧を開くとnestを一定量だけ増やし、閉じると同じ量だけ減らします。そして、+や-にはnestに1を加えた値を、×や÷にはnestに2を加えた値を優先順位として設定します。例えば、括弧を開くときにnestを増やす量が10の場合、図1では外側の×の優先順位は2、括弧内の-は11、さらに内側の+は21、括弧内の÷は12です。計算処理では、優先順位が最も高い演算子が先に選ばれるので、内側の演算から計算できます。 -
優先順位が同じ場合は、先に現れた演算子が選ばれます。
計算処理では、現在の演算子より優先順位が高い演算子が見つかったときだけ、選ぶ演算子を変更します。そのため、優先順位が同じなら、式の左側にある演算子が選ばれたままです。 -
内側の演算子は、外側の演算子より必ず高い優先順位にします。
まず、括弧の外側のnestを 、括弧を開いたときに増やす量を とします。
書き換え前の設定では、外側で最も高い優先順位は、×や÷の です。一方、括弧の内側で最も低い優先順位は、+や-の です。括弧の内側を先に計算するには、内側の最も低い優先順位でも、外側の最も高い優先順位を上回る必要があります。両辺から を引くと、、つまり です。 は整数なので、 は2以上でなければなりません。したがって、aは「2以上」です。もし だと、例えば2×(3+4) では、外側の×も内側の+も優先順位が2になります。同じ優先順位なら左側の×が先に選ばれるため、括弧の内側を先に計算できません。 -
priLowとpriHighに書き換えた場合も、同じ条件で考えます。
外側で最も高い優先順位は 、内側で最も低い優先順位は です。内側を必ず先にする条件は、次のとおりです。整理すると、 です。 は整数なので、必要なのは次の条件です。よって、bは「priHigh − priLow + 1以上」です。差と同じ値では優先順位が同じになり、括弧の内側を先にできないため、さらに1が必要です。
誤りやすいポイント
- 「括弧の内側の優先順位が外側以上」でよいと考えないようにしましょう。同じ優先順位では、左側の演算子が選ばれることがあるため、内側は外側より大きくする必要があります。
- nestを増やす量は10でなくても構いません。大切なのは、内側の演算子の優先順位が外側の演算子を上回ることです。
- priHighとpriLowの差をそのままnestの増加量にすると、内側と外側の優先順位が同じになります。整数で、かつ厳密に上回る条件にするため、差に1を加えます。
FAQ
Q: nestを増やす量が10なのは、何か特別な理由があるのですか?
A: ありません。この設定では2以上なら、括弧の内側の演算子が外側より先に選ばれます。10は条件を満たす値の一例です。
A: ありません。この設定では2以上なら、括弧の内側の演算子が外側より先に選ばれます。10は条件を満たす値の一例です。
Q: 同じ優先順位の演算子があると、必ず誤った計算になりますか?
A: いいえ。同じ括弧の深さにある演算子どうしなら、左側から計算する順序が保たれます。問題になるのは、括弧の内側と外側の演算子が同じ優先順位になり、外側が先に選ばれる場合です。
A: いいえ。同じ括弧の深さにある演算子どうしなら、左側から計算する順序が保たれます。問題になるのは、括弧の内側と外側の演算子が同じ優先順位になり、外側が先に選ばれる場合です。
Q: なぜ「以上」ではなく、式では「より大きい」とするのですか?
A: 優先順位が同じだと、括弧の内側が先に選ばれる保証がないためです。内側の優先順位が外側を厳密に上回る必要があります。
A: 優先順位が同じだと、括弧の内側が先に選ばれる保証がないためです。内側の優先順位が外側を厳密に上回る必要があります。
関連キーワード: 整数式、括弧、演算子、演算子の優先順位、整数定数
設問2:
問題文を見る 優先順位の等しい演算子が複数個含まれている整数式の、演算の実行順序について考察する。プログラムに関する次の記述中のに入れる正しい答えを、解答群の中から選べ。ここで、c1〜c3に入れる答えは、cに関する解答群の中から組合せとして正しいものを選ぶものとする。
プログラム(計算処理の部分)では、優先順位の等しい演算子が複数個含まれている場合、演算を左から順に実行するようになっている。このプログラムでは、演算を左から順に実行するか右から順に実行するかは、行c1の内容がc2かc3かで決まる。
演算の実行順序によって、計算結果が異なることがある。例えば、次の四つの整数式のケースを考える。
ケース1:(12+3+1)×4×2
ケース2:(12+3+1)÷4÷2
ケース3:(12−3−1)×4×2
ケース4:(12−3−1)÷4÷2
これらのケースのうち、演算を左から実行しても右から実行しても、プログラムによる計算結果が等しくなるのは、ケースdである。
cに関する解答群


dに関する解答群
ア:1
イ:1及び2
ウ:1及び3
エ:1及び4
模範解答
c:エ、d:ア
解説
解答の導き方
まず、計算処理の中でどの演算子を先に選ぶのかを確認します。演算子(+や−など、計算の種類を表す記号)の優先順位(どの計算を先に行うかを示す順番)は、配列Priority[]に入っています。計算処理では、演算子を選ぶときに「Priority[ip] < Priority[i]」なら、選ぶ位置ipをiに更新します。そのため、Priority[]の値が最も大きい演算子が選ばれます。
優先順位が同じ演算子が複数ある場合は、行⑦の条件が順序を決めます。元の条件は「Priority[ip] < Priority[i]」なので、同じ値どうしを比べたときは条件が成り立ちません。したがって、先に見つけた演算子が選ばれたままになります。探索は左から進むので、同じ優先順位なら左側の演算子から計算します。
右側の演算子から計算するには、同じ優先順位でも選ぶ位置を後ろへ更新できる必要があります。そのため、条件を「Priority[ip] ≤ Priority[i]」にします。探索が左から進むたび、同じ優先順位の演算子が見つかれば選ぶ位置が更新され、最後には最も右側の演算子が選ばれます。よって、c1は⑦、c2は「Priority[ip] < Priority[i]」、c3は「Priority[ip] ≤ Priority[i]」となる組合せ、すなわち選択肢エです。
次に、四つのケースについて、左から計算した場合と右から計算した場合を比べます。括弧内の計算は、括弧の外の計算より先に行われます。
-
ケース1:(12+3+1)×4×2左から計算すると、括弧内は(12+3)+1=16で、外側は(16×4)×2=128です。右から計算すると、括弧内は12+(3+1)=16で、外側は16×(4×2)=128です。どちらも128になります。
-
ケース2:(12+3+1)÷4÷2括弧内は、左右どちらから計算しても16です。左から計算すると、(16÷4)÷2=2です。右から計算すると、16÷(4÷2)=8です。結果が異なります。
-
ケース3:(12−3−1)×4×2左から計算すると、括弧内は(12−3)−1=8で、外側は(8×4)×2=64です。右から計算すると、括弧内は12−(3−1)=10で、外側は10×(4×2)=80です。結果が異なります。
-
ケース4:(12−3−1)÷4÷2左から計算すると、括弧内は(12−3)−1=8で、外側は(8÷4)÷2=1です。右から計算すると、括弧内は12−(3−1)=10で、外側は10÷(4÷2)=5です。結果が異なります。
四つのうち、左右どちらから計算しても結果が同じなのはケース1だけです。したがって、dはアです。
誤りやすいポイント
- 行⑦の条件が優先順位の大小を比べるだけでなく、同じ優先順位の演算子のどちらを選ぶかも決める点を見落としやすいです。
- 「<」では同じ値の場合に選ぶ位置が更新されず、「≤」では更新されます。この違いが、左から計算するか右から計算するかにつながります。
- +や×では今回のケースのように計算順を変えても結果が同じことがありますが、−や÷では結果が変わることがあります。ケース1だけの結果から、どの演算でも順序は関係ないと判断しないようにします。
FAQ
Q: Priority[]の値が大きい演算子ほど、先に計算されるのですか?
A: はい。計算処理では、現在選んでいる演算子よりPriority[]の値が大きいものが見つかると、選ぶ位置を更新します。図1でも、括弧内の演算子は外側の演算子より大きい優先順位になっています。
A: はい。計算処理では、現在選んでいる演算子よりPriority[]の値が大きいものが見つかると、選ぶ位置を更新します。図1でも、括弧内の演算子は外側の演算子より大きい優先順位になっています。
Q: 「右から計算する」と、括弧を無視して式全体を右から計算するのですか?
A: いいえ。まず優先順位の高い演算子が選ばれます。右から計算するというのは、優先順位が同じ演算子が複数あるときに、右側の演算子を先に選ぶという意味です。
A: いいえ。まず優先順位の高い演算子が選ばれます。右から計算するというのは、優先順位が同じ演算子が複数あるときに、右側の演算子を先に選ぶという意味です。
Q: ケース1で左右の結果が同じなのはなぜですか?
A: このケースでは、+と×の計算順を変えても結果が変わらないためです。一方、ケース2の÷やケース3・ケース4の−では、順序を変えると結果が変わります。
A: このケースでは、+と×の計算順を変えても結果が変わらないためです。一方、ケース2の÷やケース3・ケース4の−では、順序を変えると結果が変わります。
関連キーワード: 演算子の優先順位、演算子の結合順序、配列、整数演算
設問3:
問題文を見る プログラムの動作に関する次の記述中のに入れる正しい答えを、解答群の中から選べ。
符号付き整定数(数字の並びの先頭に符号+又は−を付けた定数)を含む整数式を考える。符号付き整定数は、例2のように括弧で囲んで記述する。ただし、符号付き整定数の直前の文字が演算子でない場合は、例3のように括弧で囲まなくてもよい。
例2: (+2)×((−3)+(−4))
例3: +2×(−3+(−4))
符号付き整定数を含む整数式2×(−1)についてプログラム(解析処理の部分)を実行した結果を、図3に示す。
このように、符号付き整定数を含む整数式を受け取ったとき、プログラムはe。
eに関する解答群
ア:整数式が符号付き整定数で始まる場合に、正しい値を返さない
イ:整数式中に符号 − の付いた符号付き整定数がある場合に、正しい値を返さない
ウ:整数式中に二つ以上の符号付き整定数が含まれる場合に、正しい値を返さない
エ:正しい値を返す
f, gに関する解答群
ア:−1
イ:0
ウ:1
エ:2模範解答
e:エ、f:イ、g:エ
解説
解答の導き方
この設問では、符号付き整定数の符号を、プログラムがどのように扱うかを調べます。演算子(計算の記号)は、解析処理では配列に記録されます。配列は、番号の付いた箱に値を並べておくものです。
まず、図3の整数式2×(−1)を左から読みます。
- 数字の「2」を読むと、 に2が入ります。
- 「×」を読むと、 に「×」、 に2が入ります。その後、 が1になり、次の値を入れる場所である に0が入ります。
- 「(」を読むと、 が10になります。
- 「−」を読むと、 に「−」が記録されます。符号が「+」又は「−」の場合、優先度は なので、 は11です。その後、 は2になり、 に0が入ります。
- 数字の「1」を読むと、 が1になります。
したがって、解析処理の後は、 が0、 が2です。図3の は0なので解答群のイ、 は2なので解答群のエです。
次に、計算処理でどう計算されるかを確認します。優先度は、 が2、 が11です。プログラムは優先度の高い演算子から計算するので、まず「−」を処理します。
その後、「×」を計算します。
計算結果は整数式2×(−1)の値と一致します。
この仕組みは、ほかの符号付き整定数にも使えます。プログラムは符号を特別な形式で保存するのではなく、「+」や「−」を演算子として扱います。そのとき、演算子の左側の値が0なら、正の符号は 、負の符号は として計算できます。また、括弧の中では が増えるため、その中の符号の優先度は外側の演算子より高くなります。
したがって、符号付き整定数を含む式でも正しい値を返します。 は「正しい値を返す」のエです。
誤りやすいポイント
- を−1と考えないようにします。図3は解析処理の直後の状態です。この時点ではまだ計算していないため、 は0です。−1になるのは計算処理で「0−1」を実行した後です。
- は、計算する演算子の数を表します。符号の「−」も演算子として記録されるので、この式では「×」と「−」の二つを数えます。
- 符号の「−」があるから誤答になる、と判断しないようにします。プログラムは0を使って符号の計算を表せます。
- 優先度を見るときは、括弧の中で増えた も考慮します。図3では、括弧内の「−」の優先度11が「×」の優先度2より高くなります。
FAQ
Q: なぜ「−」の左側にある値が0になるのですか?
A: 演算子を読み取るたびに、プログラムが次の値を入れる場所を0で初期化するためです。符号の「−」を読む場合、その直前に用意された0が左側の値になります。
A: 演算子を読み取るたびに、プログラムが次の値を入れる場所を0で初期化するためです。符号の「−」を読む場合、その直前に用意された0が左側の値になります。
Q: が2なのは、数値が二つあるからですか?
A: いいえ。 は数値ではなく、記録された演算子の数です。この式では「×」と符号の「−」が記録されるため2です。
A: いいえ。 は数値ではなく、記録された演算子の数です。この式では「×」と符号の「−」が記録されるため2です。
Q: 図3の時点で、式の計算は終わっていますか?
A: いいえ。図3は解析処理の直後です。演算子や優先度などの情報が配列に記録された段階で、値の計算はまだ始まっていません。
A: いいえ。図3は解析処理の直後です。演算子や優先度などの情報が配列に記録された段階で、値の計算はまだ始まっていません。
関連キーワード: 構文解析、演算子、演算子の優先順位、配列、整数演算



