令和6年度の科目B、その2問目です。“10010” という文字の並びを、18 という数にする関数を読みます。空欄は1つだけ。ただしそこには 「なぜ2倍するのか」が入っていて、そこが分からないまま解答群を眺めると、4つとも同じに見えます。この記事では、2倍する理由を自分で作れるところまで進みます。
出題
まず原文のまま読んでみてください。記号の読み方は次の節にまとめてありますので、読めなくてもここでは問題ありません。
出典:令和6年度 基本情報技術者試験 科目B 公開問題 問2
次のプログラム中の に入れる正しい答えを,解答群の中から選べ。
関数convDecimal は,引数として与えられた,“0”と“1”だけから成る,1 文字以上の文字列を,符号なしの2 進数と解釈したときの整数値を返す。例えば,引数として“10010”を与えると18 が返る。
関数convDecimal が利用する関数int は,引数で与えられた文字が“0”なら整数値0 を返し,“1”なら整数値1 を返す。
〔プログラム〕
○整数型: convDecimal(文字列型: binary)
整数型: i, length, result ← 0
length ← binaryの文字数
for (i を 1 から length まで 1 ずつ増やす)
result ←
endfor
return result
解答群
ア result + int(binary の (length - i + 1)文字目の文字)
イ result + int(binary の i文字目の文字)
ウ result × 2 + int(binary の (length - i + 1)文字目の文字)
エ result × 2 + int(binary の i文字目の文字)
答えだけ先に見る
正解は エ(result × 2 + int(binary の i文字目の文字))です。2倍がなぜ要るのか、なぜ左から読むのかを、この記事では順に作ります。
この問題に出てくる記号
読めない記号があったときだけ開いてください。いま読めればいいのは9つだけで、細かいところは使う場面で足していきます。
擬似言語の記号 9コ の読み方をひらく
| 書き方 | 読み方 |
|---|---|
○整数型: convDecimal(…) |
ここから関数が1つ始まるという印。○ のうしろの 整数型 は返すものの型、括弧の中が受け取るものです |
文字列型: binary |
binary という箱に文字の並びが入る、ということ。"10010" のように、1文字ずつが順に並んでいます |
整数型: i, length, result ← 0 |
箱を3つ用意します。← が付いているのは result のほうなので、0 が入るのは result だけです |
a ← b |
右の値を、左へ入れる。左は前の中身が消えて上書きされます。右はそのままです |
binaryの文字数 |
その文字列に何文字あるか。"10010" なら 5 です |
binary の (length - i + 1)文字目の文字 |
かっこの中を先に計算して、その番号の文字を取り出します。length = 5、i = 1 なら 5 - 1 + 1 = 5 で5文字目。この式を選ぶかどうかは、あとの節で決めます |
binary の i文字目の文字 |
左から数えて i 番目の1文字。i が 1 なら左端です |
int(…) |
関数を呼ぶ書き方。括弧の中を渡すと、答えが返ってきます。この int は文字を数に変えるもので、"0" なら 0、"1" なら 1 を返します |
for (…)endfor |
あいだの行を何度もくり返す。i を 1 から 5 まで 1 ずつ増やす なら、i が 1, 2, 3, 4, 5 と変わりながら5回実行されます。くり返しの1回ぶんを、この記事では「1周」と呼びます |
× + |
かけ算と足し算。× のほうが先に計算されますので、a × 2 + b は (a × 2) + b という意味です |
記号でつまずいたら、下の教科書から、先にそこだけ読んでください(G6-1 のような番号は、当サイトの擬似言語の教科書の第何回かを表します)。
“10010” が 18 になる仕組み(一般的な計算方法)
まず、この関数が何をするのかをプログラム抜きで確かめます(出題の「符号なし」はマイナスの数は考えない、という意味です)。
2進数は、右端から 1, 2, 4, 8, 16 … と、左へ行くほど2倍ずつ重くなる並びです。
“10010” を、重みを使って数える
上の段が出題の文字、下の段がその桁の重みです。琥珀=いま注目している桁(文字が 1)/灰=足さない桁。「次へ」で1手ずつ進みます。
① 枡の下に、その桁の重みを並べる
文字
11
20
30
41
50
重み
116
28
34
42
51
重みは右端が 1で、左へ行くほど2倍ずつ(1 → 2 → 4 → 8 → 16)。上下は同じ位置どうしが組です。
② 文字が 1 の桁だけ残す
文字
11
20
30
41
50
重み
116
28
34
42
51
残るのは 1つ目(重み 16)と 4つ目(重み 2)。文字が 0 の桁は、いくつを掛けても 0 なので足しません。
③ 残った重みを足す
足す重み
1つ目16
4つ目2
16 + 2 = 18。出題の「引数として“10010”を与えると18 が返る」と合いました。
文字が 1 の桁の重みだけを足す ── 16 + 2 = 18
ここで、数えた向きに注目してください。重みを使う計算は、右端から始まります。1, 2, 4, 8, 16 と、右から順に決まっていくからです。
ところが、プログラムは左から読む
出題の for は i を 1 から 増やします。i 文字目は左から数えた番号なので、このプログラムは左端から順に読んでいくことになります ── いま数えたのと、ちょうど逆向きです。
つまり、この問題で考えることは1つです。
この問題の勘所
重みを使わず、左から1文字ずつ読むだけで、同じ 18 にたどり着くには?
左から読んで、同じ答えにたどり着くには
まず10進数で考えます。1、2、3 と左から読んでいくとき、手もとの数はこう育ちます。
| 読んだ文字 | 手もとの数はどうなるか | 計算 | 手もとの数 |
|---|---|---|---|
| (はじめ) | まだ何もない | — | 0 |
1 |
0 の右に 1 を書く → 1 |
0 × 10 + 1 | 1 |
2 |
1 の右に 2 を書く → 12 |
1 × 10 + 2 | 12 |
3 |
12 の右に 3 を書く → 123 |
12 × 10 + 3 | 123 |
右に1文字書くと、それまでの数はひと桁ぶん左へ押し出されます。1 は一の位から十の位へ、12 は十と一の位から百と十の位へ。だから10倍して、空いた一の位に読んだ文字を入れる ── それが 12 × 10 + 3 です。
2進数でも、やることは同じ。10倍が2倍になるだけです。
1文字読むたびにやること
いまの result を2倍して、読んだ文字(0 か 1)を足す。
"10010" で、5文字ぶん実際にやってみます。2進数の桁は、もう出てきません ── ふつうの足し算とかけ算だけです。
| 何文字目 | 読んだ文字 | 計算 | result |
|---|---|---|---|
| (はじめ) | — |
— | 0 |
| 1文字目 | 1 |
0 × 2 + 1 | 1 |
| 2文字目 | 0 |
1 × 2 + 0 | 2 |
| 3文字目 | 0 |
2 × 2 + 0 | 4 |
| 4文字目 | 1 |
4 × 2 + 1 | 9 |
| 5文字目 | 0 |
9 × 2 + 0 | 18 |
18。前の節で重みを足して出した 16 + 2 = 18 と同じ数になりました。右から重みを掛けなくても、左から読むだけで同じところへ着きます。
コードの中で、空欄は「1周ぶん進めた result」を作る行
いま手でやったことを、プログラムの各行に当てはめます。for のくり返し1回ぶんを、この記事では「1周」と呼びます。
○整数型: convDecimal(文字列型: binary)
整数型: i, length, result ← 0
length ← binaryの文字数
"10010" なら 5。これがくり返す回数になる
for (i を 1 から length まで 1 ずつ増やす)
i が 1, 2, 3, 4, 5 と変わりながら5回くり返す
result ←
ここが空欄。1周ぶん進めた新しい result を作る行
endfor
for の行へ戻り、i が1増えてもう1周する
return result
育てた result を返す=呼んだ側へ渡して終わり
※ 右側の注釈は当サイトで書き加えたものです。プログラム自体は原文のまま引用しています。
result がこのプログラムの主役
result は「ここまで読んだぶんの値」。出発点は 0 で、1周ごとに result を作り直すことが「1文字読む」ことにあたります。
空欄に入るものを決める
決めるのは、この行です。
〔プログラム〕空欄のある行と、それを囲むくり返し
for (i を 1 から length まで 1 ずつ増やす)
result ←
endfor
※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。
入るのは新しい result。前の節で書き出したとおり、それはいまの result を2倍して、いま読んだ文字の値を足したものです。文字を 0 か 1 の数に変えるのが int(…) でした。
ここまでで決まったこと
result × 2 + int( いま読んだ文字 )
残るは「いま読んだ文字」をどう書くかだけです。for は i を 1 から length まで増やすので、i をそのまま文字の番号に使えば、左から順に読めます。
i = 1 のとき、どの文字を読むか
どちらも i = 1(くり返しの1周目)のときです。琥珀が、その周で読む文字。
i 文字目 と書いた場合
11
20
30
41
50
i = 1 なので 1文字目。i が増えるほど右へ進むので、左から順に読みます。
(length - i + 1) 文字目 と書いた場合
11
20
30
41
50
length = 5 なので 5 - 1 + 1 = 5、つまり 5文字目。i が増えるほど左へ戻るので、右から順に読みます。
左から読みたいので、書くのは i 文字目。
空欄に入るもの
result ← result × 2 + int(binary の i文字目の文字)
× は + より先に計算されますので、かっこは要りません((result × 2) + int(…) と同じ意味です)。
ここで初めて解答群を見る
result × 2 + int(binary の i文字目の文字)。解答群でこの式は エ ひとつだけです。
本番の手順 ── くり返しの中の ◯ ← ◯ … は、手で2〜3周ぶん作って決める
- その箱が覚えているものを、名前ではなく中身で言う。ここでは
result=「ここまで読んだぶんの値」。これが決まらないと、次に進めません。 - 2〜3周ぶんを手で並べて、前の値からの変わり方を読む。ここでは 0 → 1 → 2 → 4。2倍ずつ育っていると分かれば、式は
前の値 × 2 + 読んだ桁。変わり方がそのまま式になります。添字の向きはi= 1 を代入すれば1手で決まります。
答え合わせ ── result が 0 から 18 まで育つ
空欄に エ を入れて、convDecimal("10010") を最後まで動かします。result の欄と、いま読んでいる文字(▲)を見てください。
1行ずつ追う 正解の エ(result × 2 + int(binary の i文字目の文字))
出典:令和6年度 科目B 公開問題 問2(空欄に エ を入れたもの)
ループ開始前
binary の文字(左から1文字ずつ。読むだけで、書き換えません)
いま計算していること
変数の状態
return で返した値
トレース表(進めると1行ずつ積み上がります)
正解は エ
result ← result × 2 + int(binary の i文字目の文字)。2倍が「桁を1つ上げる」役、int(…) が「新しい桁を足す」役です。
ほかの3つは、この2つの役のどちらかが壊れています。解答群の4つは、「2倍あり/なし」と「左から/右から」の組合せでできていました。
| 選択肢 | "10010" で返る値 |
何が起きるか |
|---|---|---|
result + int(… (length - i + 1)文字目 …)(ア) |
2 | 2倍が無いので桁が上がらず、1 の文字を数えているだけになります |
result + int(… i文字目 …)(イ) |
2 | 同じく2倍が無い。ア と イ は返す値がいつも同じです ── どちらも全部の文字を1回ずつ足すだけなので、読む向きは和に効きません |
result × 2 + int(… (length - i + 1)文字目 …)(ウ) |
9 | 2倍はありますが右から読んでいます。10010 を逆に並べた 01001 を読んだ値です |
「1文字ずつ数を育てる」問題を見分ける
同じ形は、このあと何度も出てきます。見るところは2つです。
| 見るところ | 読み取ること |
|---|---|
| この形だと気づく合図 | 結果を入れる箱が1つだけあって、くり返しの中でその箱に、その箱自身を使って代入している(result ← result …)。途中の値をぜんぶ並べて残す入れ物がないのが目印です |
| 倍率は、その数の「桁の上がり方」で決まる | 2進数なら2倍、10進数なら10倍。足すだけの集計なら倍率はありません(× 2 のような項が式に出てこない)。何進数の話かを先に決めると、倍率が自動で決まります |
次に読む
この問題でどこに手間取ったかで、行き先が変わります。
if の連鎖から最大値を返しますG6-1繰返し for ── i が何回、どう変わるかが曖昧だった人へG8-1算術演算子と優先順位 ── × と + のどちらが先か迷った人へ一覧科目B 全44問の解説 ── 同じ形の問題を続けて解きたい人へこの記事で引用した資料
いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

