空欄は2行まるごと。式を読み解くのは難しいので、4つの選択肢を全部動かして、おかしくなったものから消します。
本番での扱い
1問あたりの目安は約5分(科目Bは100分で20問)。選択肢を8回ずつ動かすこの問題は後回しにして、時間が残ったら戻るのが得策です。
難易度 ★★★(当サイトの目安)── シフトと論理積を何周か追わないと、選択肢を見分けられない。4段階の決め方は科目B 最短合格の戦略にあります。
出題
出典:基本情報技術者試験 科目B サンプル問題 問6
次のプログラム中の に入れる正しい答えを,解答群の中から選べ。
関数rev は8 ビット型の引数byte を受け取り,ビットの並びを逆にした値を返す。例えば,関数rev をrev(01001011) として呼び出すと,戻り値は11010010 となる。
なお,演算子 ∧ はビット単位の論理積,演算子 ∨ はビット単位の論理和,演算子 >> は論理右シフト,演算子 << は論理左シフトを表す。例えば,value >> n はvalue の値をn ビットだけ右に論理シフトし,value << n はvalue の値をn ビットだけ左に論理シフトする。
〔プログラム〕
○8 ビット型: rev(8 ビット型: byte)
8 ビット型: rbyte ← byte
8 ビット型: r ← 00000000
整数型: i
for (i を 1 から 8 まで 1 ずつ増やす)
endfor
return r
解答群
ア r ← (r << 1) ∨ (rbyte ∧ 00000001)
rbyte ← rbyte >> 1
イ r ← (r << 7) ∨ (rbyte ∧ 00000001)
rbyte ← rbyte >> 7
ウ r ← (rbyte << 1) ∨ (rbyte >> 7)
rbyte ← r
エ r ← (rbyte >> 1) ∨ (rbyte << 7)
rbyte ← r
答えだけ先に見る
正解は アです。
この問題に出てくる記号
読めない記号があったときだけ開いてください。
記号 4コ の読み方をひらく
| 書き方 | 読み方 |
|---|---|
a ∧ b |
桁ごとに、両方 1 なら 1、それ以外は 0 |
a ∨ b |
桁ごとに、どちらかが 1 なら 1 |
a << n |
全体を左へ n 桁ずらす。はみ出た桁は捨て、右端には 0 が入る |
a >> n |
全体を右へ n 桁ずらす。はみ出た桁は捨て、左端には 0 が入る |
コードは何をしているか
〔プログラム〕
8 ビット型: rbyte ← byte
8 ビット型: r ← 00000000
整数型: i
for (i を 1 から 8 まで 1 ずつ増やす)
endfor
return r
※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。
r は 00000000 から始まり、最後に return r で返されます。for で8回まわるあいだに、r を byte の並びを逆にしたものに仕上げるのが空欄の仕事です(rbyte は byte の写しで、作業用)。
空欄に入るものを決める ── 4つとも動かして確かめる
選択肢の式が何をしているかを読み解くのは難しいので、4つとも実際に動かします。入れるのは問題文の例 01001011。正しい選択肢なら、8回後の r は 11010010 になります。
使う記号は4つだけです。
<< n── 全体を左へ n 桁ずらす。左端からはみ出た桁は捨て、右端には 0 が入る>> n── 全体を右へ n 桁ずらす。右端からはみ出た桁は捨て、左端には 0 が入る∧ 00000001── 右端の桁だけが残り、ほかはすべて 0∨── 桁ごとに、どちらかが 1 なら 1
byte = 01001011 で、4つの選択肢を動かす(各回が終わったあとの値)
緑=その回で新しくできた値
ア r ← (r << 1) ∨ (rbyte ∧ 00000001)
rbyte ← rbyte >> 1
→ 11010010 で正しい
1回目を筆算で
1行目 r ← (r << 1) ∨ (rbyte ∧ 00000001)
(1) r << 1 00000000 → 00000000
(0 はずらしても 0)
(2) rbyte ∧ 00000001
01001011
00000001 ∧
────────
00000001 右端だけ残る
(3) (1) ∨ (2)
00000000
00000001 ∨
────────
00000001 = 新しい r
2行目 rbyte ← rbyte >> 1
01001011 → 00100101
各回が終わったあとの値
1回目 r = 00000001 rbyte = 00100101 2回目 r = 00000011 rbyte = 00010010 3回目 r = 00000110 rbyte = 00001001 4回目 r = 00001101 rbyte = 00000100 5回目 r = 00011010 rbyte = 00000010 6回目 r = 00110100 rbyte = 00000001 7回目 r = 01101001 rbyte = 00000000 8回目 r = 11010010 rbyte = 00000000
2回目からも同じ4つをくり返します。r は1つ左へずれてから右端に rbyte の右端が入り、rbyte は1つ右へ。
イ r ← (r << 7) ∨ (rbyte ∧ 00000001)
rbyte ← rbyte >> 7
→ 3回目で消去
1回目を筆算で
1行目 r ← (r << 7) ∨ (rbyte ∧ 00000001)
アと同じで 00000001 = 新しい r
2行目 rbyte ← rbyte >> 7
01001011 → 00000000
(7桁がはみ出し、左端の 0 だけ残る)
各回が終わったあとの値
1回目 r = 00000001 rbyte = 00000000 2回目 r = 10000000 rbyte = 00000000 3回目 r = 00000000 rbyte = 00000000
rbyte は1回目の >> 7 でもう 00000000。r の 1 は7桁ずつ左へ動いて3回目にはみ出し、r も rbyte も 00000000。ここから先は何度くり返しても 0 のままなので、ここで消せます。
ウ r ← (rbyte << 1) ∨ (rbyte >> 7)
rbyte ← r
→ 01001011 で外れ
1回目を筆算で
1行目 r ← (rbyte << 1) ∨ (rbyte >> 7)
(1) rbyte << 1 01001011 → 10010110
(2) rbyte >> 7 01001011 → 00000000
(3) (1) ∨ (2)
10010110
00000000 ∨
────────
10010110 = 新しい r
2行目 rbyte ← r → rbyte も 10010110
(2) は、7桁が右端からはみ出して左端の1桁だけが右端に残る。いまは左端が 0 なので 00000000(左端が 1 なら 00000001)。
各回が終わったあとの値
1回目 r = 10010110 2回目 r = 00101101 3回目 r = 01011010 4回目 r = 10110100 5回目 r = 01101001 6回目 r = 11010010 7回目 r = 10100101 8回目 r = 01001011
2行目 rbyte ← r で、次の回はいま作った r が rbyte(なので r だけ書けば足ります)。毎回、左端の桁が右端へ回るだけなので、8回目で元の 01001011 に戻ります。
エ r ← (rbyte >> 1) ∨ (rbyte << 7)
rbyte ← r
→ 01001011 で外れ
1回目を筆算で
1行目 r ← (rbyte >> 1) ∨ (rbyte << 7)
(1) rbyte >> 1 01001011 → 00100101
(2) rbyte << 7 01001011 → 10000000
(3) (1) ∨ (2)
00100101
10000000 ∨
────────
10100101 = 新しい r
2行目 rbyte ← r → rbyte も 10100101
(2) は、7桁が左端からはみ出して右端の1桁だけが左端に残る。右端は 1 なので 10000000。
各回が終わったあとの値
1回目 r = 10100101 2回目 r = 11010010 3回目 r = 01101001 4回目 r = 10110100 5回目 r = 01011010 6回目 r = 00101101 7回目 r = 10010110 8回目 r = 01001011
ウと同じく次の回はいま作った r が rbyte。毎回、右端の桁が左端へ回るだけ。8回目で元に戻ります。
途中で消せたのはイだけで、ウ・エは8回目まで追って初めて外れと分かります。最後まで残ったのはアです。
エは2回目、ウは6回目に 11010010 を通ります。それでも答えは8回後の値です。途中で飛びつかず、最後まで数えます。
答え合わせ
正解は ア です。
r ← (r << 1) ∨ (rbyte ∧ 00000001) rbyte ← rbyte >> 1
アは、rbyte の右端のビットを1つ取り出して、r の右端に積みます。積むたびに r は1つ左へずれるので、最初に積んだビットほど左へ押し出され、並びが逆になります。1行ずつの動きは下で追えます。
1行ずつ追う 正解の ア で rev(01001011)
出典:科目B サンプル問題 問6(空欄に ア を入れたもの)
ループ開始前
いま計算していること
変数の状態
return で返した値
トレース表(進めると1行ずつ積み上がります)
次に読む
この問題でどこに手間取ったかで、行き先が変わります。
この記事で引用した資料
いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

