追うのではなく計算する回です。同じ式を5つの p にあてはめるだけで、決め手は 「小数点以下を切り上げた値」 と sortedData[i + 1] の +1 の2か所しかありません。
難易度 ★★★(当サイトの目安)── 関数2つを行き来しながら、小数の切り上げを5回計算する。4段階の決め方は科目B 最短合格の戦略にあります。
出題
読めない記号があっても大丈夫です。次の節にまとめてあります。
出典:基本情報技術者試験 科目B サンプル問題 問14
次の記述中の に入れる正しい答えを,解答群の中から選べ。ここで,配列の要素番号は1 から始まる。
要素数が1 以上で,昇順に整列済みの配列を基に,配列を特徴づける五つの値を返すプログラムである。
関数summarize をsummarize({0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1})として呼び出すと,戻り値は である。
〔プログラム〕
○実数型: findRank(実数型の配列: sortedData, 実数型: p)
整数型: i
i ← (p × (sortedDataの要素数 - 1)) の小数点以下を切り上げた値
return sortedData[i + 1]
○実数型の配列: summarize(実数型の配列: sortedData)
実数型の配列: rankData ← {} /* 要素数0の配列 */
実数型の配列: p ← {0, 0.25, 0.5, 0.75, 1}
整数型: i
for (i を 1 から pの要素数 まで 1 ずつ増やす)
rankDataの末尾 に findRank(sortedData, p[i])の戻り値 を追加する
endfor
return rankData
解答群
ア {0.1, 0.3, 0.5, 0.7, 1} / イ {0.1, 0.3, 0.5, 0.8, 1}
ウ {0.1, 0.3, 0.6, 0.7, 1} / エ {0.1, 0.3, 0.6, 0.8, 1}
オ {0.1, 0.4, 0.5, 0.7, 1} / カ {0.1, 0.4, 0.5, 0.8, 1}
キ {0.1, 0.4, 0.6, 0.7, 1} / ク {0.1, 0.4, 0.6, 0.8, 1}
※ 解答群は原本では縦8行。ここでは2つずつ4行にまとめました(字句は変えていません)。
答えだけ先に見る
正解は ク({0.1, 0.4, 0.6, 0.8, 1})です。
この問題に出てくる記号
擬似言語の記号 ── 読み方の早見表をひらく
| 書き方 | 読み方 |
|---|---|
○実数型: findRank(実数型の配列: sortedData, 実数型: p) |
ここから関数 findRank が始まるという印。実数の配列と実数を1つずつ受け取り、実数を1つ返します |
○実数型の配列: summarize(…) |
こちらが返すのは実数の配列。値1つではなく、いくつか並んだものを返します |
← {} |
右の値を、左の箱へ入れるという印/中身が1つも無い配列(要素数0) |
sortedData[i + 1] sortedDataの要素数 |
配列 sortedData の i + 1 番目の値/入っている値の個数。要素番号は 1 から始まります |
… の小数点以下を切り上げた値 |
小数点以下があれば1つ上の整数へ上げる。3.1 → 4、7.5 → 8。もともと整数ならそのまま(6 → 6) |
return sortedData[i + 1] |
その値を返して、関数をその場で抜ける。findRank はここで終わり、呼んだ側(summarize)へ戻ります |
rankDataの末尾 に … を追加する |
配列のうしろに1つ足す。要素数が1つ増えます |
for (i を 1 から pの要素数 まで 1 ずつ増やす) /* … */ |
i を 1, 2, 3 … と pの要素数 まで変えながら endfor までをくり返す/注釈(読む人への説明で、実行には関係ありません) |
式をあてはめる ── 5回のうち、はじめの2回
値を出すのは findRank の2行です。summarize のほうは、この2行を5回ぶん呼んで、返ってきた値を rankData のうしろに並べているだけ。
同じ名前の箱が2つずつあるので、先に分けておきます。summarize の p は {0, 0.25, 0.5, 0.75, 1} という配列で、その i 番目 p[i] を findRank の p(実数1つ)として渡します。i も別物で、summarize の i は何回目か(1〜5)、findRank の i は何番目の枡を取るかです。下の図では、回ごとにどちらの i・p がいくつなのかを、筆算の頭に並べてあります。
〔プログラム〕findRank の、値を出す2行
i ← (p × (sortedDataの要素数 - 1)) の小数点以下を切り上げた値 return sortedData[i + 1]
※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。
呼び出しで渡した {0.1, 0.2, …, 1} が、この sortedData です。10個あるので sortedDataの要素数 - 1 は 9。どの回でもこの 9 は変わりません。
解答群の割れ方 → findRank は5回 → あてはめ(1回目・2回目)
?= まだ決めていない枡/▲と琥珀の枡= このとき取り出す枡
① 解答群8つに共通しているところ
戻り値(=解答群の形)
10.1
2?
3?
4?
51
解答群を縦に見ると、1番目は8つとも 0.1、5番目は8つとも 1。割れているのは 2番目(0.3 か 0.4)・3番目(0.5 か 0.6)・4番目(0.7 か 0.8) の3か所だけです。つまり決め手は真ん中の3つで、そこを出せば決まります。
② summarize は findRank を 5回呼ぶ
呼び出しの一覧
pの要素数 は 5 → for は 5周 findRank(sortedData, p[i]) を i=1〜5 で 5回 i = 1 → p[1] = 0 を渡す i = 2 → p[2] = 0.25 を渡す i = 3 → p[3] = 0.5 を渡す i = 4 → p[4] = 0.75 を渡す i = 5 → p[5] = 1 を渡す 1つ目の引数 sortedData は 5回とも同じ配列
summarize がすることは、この5回の呼び出しと、戻ってきた5つを rankData へ順に並べることだけです。値を出しているのは、いつも findRank の2行。ちがうのは渡す p だけなので、同じ筆算を5回やることになります。
③ 1回目 p = 0 ── まず、式の読み方を覚える
筆算
呼び出し(1回目)
findRank(sortedData, p[1]) → findRank(sortedData, 0)
findRank の中では p = 0
i を出す
p × (sortedDataの要素数 - 1)
= 0 × (10 - 1)
= 0 × 9
= 0
小数点以下を切り上げて i = 0
返す値
sortedData[i + 1]
= sortedData[0 + 1]
= sortedData[1]
= 0.1
sortedData の 1番目
10.1▲
0 × 9 は 0。もともと整数なので、切り上げても i = 0 のままです。返すのは sortedData[0 + 1] = 1番目の 0.1。要素番号は 1 から始まるので 0番目という枡はありません ── + 1 があるおかげで、i が 0 でも1番目を指せます。図①の1番目も 0.1 でしたから、読み方は合っています。
④ 2回目 p = 0.25 ── ここで、割れていた2番目が決まる
筆算
呼び出し(2回目)
findRank(sortedData, p[2]) → findRank(sortedData, 0.25)
findRank の中では p = 0.25
i を出す
p × (sortedDataの要素数 - 1)
= 0.25 × (10 - 1)
= 0.25 × 9
= 2.25
小数点以下を切り上げて i = 3
返す値
sortedData[i + 1]
= sortedData[3 + 1]
= sortedData[4]
= 0.4
sortedData の 3番目と4番目
30.3
40.4▲
2.25 の小数点以下を切り上げると 3 で、取り出すのは sortedData[3 + 1] = 4番目の 0.4。もし切り捨てて 2 にしていたら sortedData[3] = 0.3 で、隣の枡になります。解答群の2番目はこの 0.3 と 0.4 で割れていました。
小数点以下を切り上げるか切り捨てるかで、取り出す枡が1つずれます。ここが、この問題でいちばん間違えるところです。
同じ筆算を5回続けて決める
あとは、いまの筆算を p = 0.5・0.75・1 についてもやるだけです。5回続けると、こうなります。
p |
p × 9 |
i |
i + 1 |
値 |
|---|---|---|---|---|
0 |
0 |
0 |
1 |
0.1 |
0.25 |
2.25 |
3 |
4 |
0.4 |
0.5 |
4.5 |
5 |
6 |
0.6 |
0.75 |
6.75 |
7 |
8 |
0.8 |
1 |
9 |
9 |
10 |
1 |
i は p × 9 の小数点以下を切り上げた値。i + 1 が、sortedData から取り出す枡の番号です。
p × 9 が整数になるのは1行目と5行目だけ(0 と 9)。そこだけ切り上げが効かないので、解答群の1番目と5番目が8つとも同じだったのは、このためです。
解答群を見る
右の列を上から読むと {0.1, 0.4, 0.6, 0.8, 1} ── ク です。
答え合わせ
ク {0.1, 0.4, 0.6, 0.8, 1}
外れる7つの出どころもひとことで。切り上げるところを切り捨てると、真ん中の3つが1つずつ前にずれて {0.1, 0.3, 0.5, 0.7, 1} ── 解答群の ア になります。+ 1 を落とした場合も同じ向きにずれるので、この問題で守るのは「切り上げ」と「+ 1」の2つだけです。
次に読む
この問題でどこに手間取ったかで、行き先が変わります。
この記事で引用した資料
いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

