平成29年度春期午後のC言語問題である問9の私の解き方・考え方について解説していきます。
問題
IPAの公式サイトで公開されています。このページでは問9についての解説を行います。
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2017h29_1/2017h29h_fe_pm_qs.pdf
問題の概要
マーク式答案の採点に関する問題ですね。論理演算の知識が問われる問題です。
例えば問題の図2のように正答や解答は下記のようなビット列として扱われます。
スポンサーリンク
設問1
設問1はプログラムの穴埋めです。
ポイントは複数解答する形式の問題に関する採点の仕方だと思います。
i問目の正答とユーザ解答は図2のようにビット列としてansC[i]およびansE[i]に格納されています。
またi問目の正答の個数はtype[i]に格納されており、このtype[i]によって採点方法が違うことが表1に記載されています。
この辺りをしっかり把握しておきましょう。
それではプログラムを見ていきます。
緑枠はtype[i]が1の時の処理です。
青枠はtype[i]が2から8の時の処理です。表1の下側にこの時の処理が記載されており、「ansE[i]の中の1のビットの個数がn+1個以上なら0、n個以下なら、ansC[i]とansE[i]の対応するビットがともに1である個数」を点数としています。この採点処理をC言語で書けば、[ a ]、[ b ]、[ c ]の答えがわかることになります。
まず「ansE[i]の中の1のビットの個数」を取得する方法を考えましょう。countMarkBits関数は「引数で指定された値に含まれる1のビットの個数を返却する」関数です。ですので、「ansE[i]の中の1のビットの個数」はcountMarkBits(ansE[i])を実行することで取得できます。したがって[ a ]の答えはansE[i]となります。
さらに、「1のビットの個数がn+1個以上なら0、n個以下なら・・・」の部分を考えましょう。これはn個以下でないと採点処理はしないという意味です。表1からnはtype[i]の値と考えられますし、青枠内のcountMarkBits(ansE[i])でansE[i]の1のビットの個数が返却されてきますので、countMarkBits(ansE[i]) <= type[i]の時のみ次の処理が実行するプログラムにする必要があります。したがって[ b ]の答えはtype[i]です。
青枠内の一番深いif文の中の処理は「ansC[i]とansE[i]の対応するビットがともに1である個数」を計算し、結果を点数としてmark[i]に格納する処理です。
countMarkBits関数を使用しているので引数に、ansC[i]とansE[i]の両方で1の値であるビットのみを1の値としたものを指定してやれば「ansC[i]とansE[i]の対応するビットがともに1である個数」が計算可能です。
ここは論理積の知識があれば簡単に解けますね。
論理積とは値Aと値Bの各ビットで両方が1のビットのみを1とし、他のビットは0にする計算です。
表2のansC[11]とansE[11]で具体的に見てみましょう。
ansC[11]:0100100000000000
ansE[11]:0101000000000000
左から1ビット目は両方が1ですので論理積結果も2ビット目は1となります。
左から4ビット目と5ビット目は片方しか1ではありませんので、論理積結果は0となります。
論理積はC言語では「&」で表されます。2つの論理積結果は下記となり、ansC[11]とansE[11]の両方で1の値であるビットのみを1の値としたものが得られます。
ansC[11] & ansE[11]:0100000000000000
したがってmarkCountBits関数への引数はansC[i] & ansE[i]となり、[ c ]の答えはansC[i] & ansE[i]です。
設問2
次はmarkCountBits関数の中身に関する問題です。
[ d ]はworkを[0101000000000000]とした時のγ実行後のworkの値となります。実際に計算してみると答えが出てきます。
work :0101000000000000
work – 1:0100111111111111
ですので、
work & (work – 1):0100000000000000
となります。ですので[ d ]は「0100000000000000」です。
[ e ]は「&」と「&&」の違いを知っていればすぐ解ける問題です。論理積を取るのは「&」であり、「&&」は条件文などに使われる演算子で、左辺と右辺が両方trueの時にtrueとなりビット毎に論理積を求める演算子ではありません。
動きが異なるので[ e ]は選択肢イとなります。
設問3
設問3は順不同形式も採点できるプログラムについての問題になります。実際にプログラムを実行した結果が問われているので単純にプログラムの動きを追って行ってやれば答えは導けます。
ポイントは「|」で表される論理和でしょうか。論理和では論理積と違って2つの値のうち一方でも1の値のビットは1にした結果となります。
表2のansC[11]とansE[11]で具体的に見てみましょう。
ansC[11]:0100100000000000
ansE[11]:0101000000000000
左から2ビット目は両方が1なので論理和結果でも左から2ビット目は1となります。
左から4ビット目と5ビット目は片方のみ1ですが、論理和ではこのビットも1となります。
したがってansC[11] | ansE[11]は下記となります。
ansC[11] | ansE[11]:0101100000000000
プログラムを見てみると、順不同形式の最初の問であるtypeが11の場合にsumCとsumEを0に初期化し、順不同形式の全ての問題でsumCをsumCとansC[i]の論理和に更新しています。つまり、sumCに順不同形式の全ての問題に対する正答のビット列ansCを覚えさせていく処理と考えられます。ansC[i]で1の値であるビットはsumCでも1にさせておき、これをループさせることで順不同形式の全ての問題のansC[i]で1の値であるビットはsumCでも1となります。
実際に問題で出てくる問20、問21、問22に関してプログラムを実行すればsumCの値は
ansC[20]:0100000000000000
ansC[21]:0001000000000000
ansC[22]:0000100000000000
sumC:0101100000000000
となり、ansC[20]からansC[22]までの正答のビットが全て1となります。
またsumEに関しても同様に論理和でsumEをansE[i]から計算しています。1点違うのは1のビット数が1つでないのであれば論理和を計算していないところです。ユーザの解答が1つでなければその問題は採点しない処理になっているようです。
問20から問22までに対してプログラムを実行するとsumEは下記のようになります。
ansE[20]:0000100000000000
ansE[21]:0000100000000000
ansE[22]:0101000000000000
sumE:0000100000000000
ansE[22]に関しては1のビットが2つ以上あるのでsumEには反映されません。
順不同形式の最終問題であるtypeが13の場合のみ、mark[i]に採点結果が格納されます。ここの採点方法は設問1と同じですね。
最終問題の時しかmark[i]には値が入らない(0のまま)であることはポイントですね。
ここまで分かれば問題は解けますね。[ f ]ではmark[20]とmark[21]とmark[22]の値が問われています。最終問題ではないmark[20]とmark[21]は0のままになります。
mark[22]はsumCとsumEの論理積結果の1のビットの数ですので、実際に論理積をとってみればわかります。
sumC:0101100000000000
sumE:0000100000000000
sumC & sumE:0000100000000000
ですので、mark[22]は1となります。したがって[ f ]は選択肢アが答えになります。
[ g ]はプログラムsumEのビット列を答えれば良いです。[ f ]が解けていれば簡単ですね。[ g ]の答えは選択肢イになります。解いてみた感想
設問1と設問2に関してはめちゃめちゃ簡単な問題だと思います。平成30年春期も簡単でしたがこっちの方が簡単ですね。
ただ論理演算の知識が必要ですのでその分敷居は高い問題なのかもしれません。この知識さえあれば簡単な問題です。
★オススメページ★
下記ページから他の回の解説もたどれます。他の回のC言語問題の解き方がわからない場合は是非読んでみてください!
本ページの図・プログラム・問題文について
図やプログラム、問題文はIPA公開の過去問題から引用しています。また図やプログラムに関しては説明に必要な部分に関してのみ加工して使用させていただいております。
出典:平成29年度 春期 基本情報技術者試験(FE)試験区分 午後 問9