令和5年度 基本情報技術者試験 科目B 問1の解説|素数を集める二重ループ

基本情報技術者試験

令和5年度 科目B 公開問題 問1擬似言語・二重ループ・フラグ変数最終更新 2026-09-08

令和5年度の科目B、その1問目です。プログラムは18行あって for が入れ子になっていますが、決め手は3つです ── どちらの for が「調べる対象」を回しているか、どちらが「割ってみる相手」を回しているか、そして条件式をよく読むこと。この2つの for の役目さえ決まれば、解答群に頼らずに空欄 a・b を自分で書き下せます(合っているかを照らすのは、いちばん最後です)。

出題

まず原文のまま読んでみてください。記号の読み方は次の節にまとめてありますので、読めなくてもここでは問題ありません。

出典:令和5年度 基本情報技術者試験 科目B 公開問題 問1

次のプログラム中の  a  と  b  に入れる正しい答えの組合せを,解答群の中から選べ。ここで,配列の要素番号は1 から始まる。

関数findPrimeNumbers は,引数で与えられた整数以下の,全ての素数だけを格納した配列を返す関数である。ここで,引数に与える整数は2 以上である。

〔プログラム〕

○整数型の配列: findPrimeNumbers(整数型: maxNum)
  整数型の配列: pnList ← {}  // 要素数0の配列
  整数型: i, j
  論理型: divideFlag
  for (i を 2 から  a  まで 1 ずつ増やす)
    divideFlag ← true

    /* iの正の平方根の整数部分が2未満のときは,繰返し処理を実行しない */
    for (j を 2 から iの正の平方根の整数部分 まで 1 ずつ増やす)  // α
      if ( b )
          divideFlag ← false
          αの行から始まる繰返し処理を終了する
      endif
    endfor
    if (divideFlag が true と等しい)
      pnListの末尾 に iの値 を追加する
    endif
  endfor
  return pnList

解答群

ア a = maxNum / b = i ÷ j の余り が 0 と等しい

イ a = maxNum / b = i ÷ j の商 が 1 と等しくない

ウ a = maxNum + 1 / b = i ÷ j の余り が 0 と等しい

エ a = maxNum + 1 / b = i ÷ j の商 が 1 と等しくない

※ 解答群の原本は a・b を2つの列に分けた表です。当サイトでは1行にまとめて引用しました(字句は変えていません)。

答えだけ先に見る

正解は アです。ほかの3つが駄目な理由も、数を入れて確かめます。

この問題に出てくる記号

読めない記号があったときだけ開いてください。この表にあるだけ読めれば足ります。細かいところは使う場面で足していきます。

擬似言語の記号の読み方をひらく
書き方 読み方
○整数型の配列: findPrimeNumbers(…) ここから関数が1つ始まるという印。○ のうしろが返すものの型(ここでは整数の配列)、括弧の中が受け取るものです
整数型の配列: pnList ← {} pnList という配列を1つ用意し、{}(要素が0個の配列)を入れる。← は右のものを左へ入れるという印です
論理型: divideFlag divideFlag という箱を1つ用意する。論理型 なので true(真)か false(偽)しか入りません
// 注釈
/* 注釈 */
どちらも人間へのメモで、実行されません
for (i を 2 から ◯ まで 1 ずつ増やす)
endfor
i を 2、3、4 … と増やしながら、あいだの行をくり返す。◯ のときも実行され、◯ を超えたところで終わります。始まりの数がすでに ◯ を超えていたら、1 回も実行されません(2 から 1 まで なら 0 回)
if (…)
endif
かっこの中が成り立つときだけ、あいだの行を実行する(成り立つことを真、成り立たないことを偽といいます)
αの行から始まる繰返し処理を終了する // α と書かれた for を途中でやめて抜ける。次に実行されるのは、その endfor の下の行です
pnListの末尾 に iの値 を追加する 配列 pnList のいちばんうしろに、i の値を1つ足す。配列は1つ長くなります
iの正の平方根の整数部分 i の平方根(2 乗すると i になる数)の、小数を捨てた数。i が 9 なら平方根はちょうど 3、i が 10 なら 3.16… なので、どちらも3 です
i ÷ j の余り
i ÷ j の商
i を j で割ったときの余りと商。7 ÷ 2 なら商が 3、余りが 1 です

記号でつまずいたら、下の教科書から、先にそこだけ読んでください(G6 のような番号は、当サイトの擬似言語の教科書の第何回かを表します)。

素数かどうかは、割り算の余りだけで決まる

素数とは、2 以上の整数で、1 と自分自身のほかには割り切れる数を持たないものです。2、3、5、7、11 … と続きます。

調べ方は割り算だけです。ある数を 2、3、4 … と順に割ってみて、1 回でも割り切れたら素数ではない。1 回も割り切れなければ素数。「割り切れた」は余りが 0 ということです(10 ÷ 2 は余り 0、10 ÷ 3 は余り 1)。擬似言語では、この余りを i ÷ j の余り と書きます。

知っておくのは、これで全部です。あとはプログラムを読みます。

2つの for は、それぞれ何を回しているか

この問題のポイントは、ここです。for が2つ、入れ子になっています。どちらが「素数かどうかを調べる対象」を回していて、どちらが「割ってみる相手」を回しているのか ── これが決まれば、あとは条件式を読むだけになります。

決め方は、その for の中で、回している変数がどう使われているかを見ることです。

2つの for は、別のものを回している

①は、あいだの行を …… で省いています(当サイト)。それ以外は〔プログラム〕のままです。

① 外側の for が回しているのは i

  for (i を 2 から  a  まで 1 ずつ増やす)
    divideFlag ← true
      ……
    if (divideFlag が true と等しい)
      pnListの末尾 に iの値 を追加する
    endif
  endfor
  return pnList

pnList は、この関数が返す配列です。そこに足しているのは i の値 ── つまり i は「素数かどうかを調べる対象」。外側の for は、その対象を 2 から順に送り出しています。

② 内側の for が回しているのは j

    for (j を 2 から iの正の平方根の整数部分 まで 1 ずつ増やす)  // α
      if ( b )
          divideFlag ← false
          αの行から始まる繰返し処理を終了する
      endif
    endfor

内側の for の中にあるのは、空欄 b の if ひとつだけです。そして divideFlag を false に倒すのは、プログラム全体でここ 1 か所 ── 倒れた i は、①の pnList に入りません。(出題の全文を見ても、divideFlag ← false はこの行だけです)。つまり空欄 b は「その i は素数ではない」と決める条件で、その判定を j を 1 つずつ変えながらくり返しています。素数は「1 回でも割り切れたら素数ではない」で決まるのでしたから、j は「i を割ってみる相手」です。

③ すると、j の上限の役目も決まる

    for (j を 2 から iの正の平方根の整数部分 まで 1 ずつ増やす)  // α

j が「割ってみる相手」だと決まったので、その上限に書いてある iの正の平方根の整数部分 の役目も決まります ── 割ってみる相手を、どこまで試すかです。この値がいくつになるかを知らなくても、置かれている場所から役目は読めます。

i = 調べる対象 / j = 割ってみる相手。

役目が決まったので、空欄の2つも、それぞれ何を書く場所なのかが決まりました。a は調べる対象をどこまで送るか、b は割り切れたかどうかを見る式です。

空欄に入るものを決める

a に入るものを決める

〔プログラム〕空欄 a のある行

  for (i を 2 から  a  まで 1 ずつ増やす)

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

この for が送り出した i が、そのまま候補になります(2 から始まっているのは、素数が 2 以上だからです)。逆に言えば、ここで送らなかった数は、素数でも答えに入りません。

関数が返すのは「引数で与えられた整数以下の,全ての素数」。引数は maxNum ですから、送ってよい上限も maxNum です。for は上限そのものも実行する書き方なので、maxNum と書けば maxNum まで調べられます。

a に入るもの

for (i を 2 から maxNum まで 1 ずつ増やす)

1 つ多く送ると、maxNum より大きい数まで候補になります。それが素数だったとき、「maxNum 以下」ではない数が答えに混ざります。

b に入るものを決める

この if が「i が j で割り切れたかどうか」を見る行だ、というところまでは決まりました。ここからは条件式そのものを読みます。

〔プログラム〕空欄 b のある行(内側の繰返しごと)

    for (j を 2 から iの正の平方根の整数部分 まで 1 ずつ増やす)  // α
      if ( b )
          divideFlag ← false
          αの行から始まる繰返し処理を終了する
      endif
    endfor

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

b が満たすこと

真になったら その i は答えに入らない。素数なのに真になったら誤り

どの j でも偽なら その i は答えに入る。素数でないのに全部偽なら誤り

はじめに決めた手順は「1 回でも割り切れたら素数ではない」でした。b は j を 1 つ受け取るたびに評価される行なので、そこに書くのは「その j で割り切れたか」 ── つまり i ÷ j の余りが 0 です。

b に入るもの

if (i ÷ j の余り が 0 と等しい)

本番の手順 ── for が入れ子になっていたら

  1. それぞれの for が何を回しているかを、先に決める。決め手は、回している変数がその中でどう使われているか。この問題なら「pnList に足しているのは i」「divideFlag を倒すのは、内側の for の中の 1 か所だけ」。
  2. 役目が決まると、上限や条件の役目も決まる。知らない書き方が上限に置かれていても、置かれている場所から役目は読めます。この問題の iの正の平方根の整数部分 がそれです。
  3. そこまで来てから、条件式を読む。「割り切れた」と言葉にできていれば、似た式が並んでいても照合するだけで済みます。先に選択肢を当てはめにいくと、4 通りを全部たどることになります。

ここで解答群と照らす

a は maxNum、b は i ÷ j の余り が 0 と等しい。この組合せは ア ひとつだけです。

答え合わせ ── 入れて動かすと {2, 3, 5, 7} が返る

空欄に ア を入れて、maxNum が 10 のときを最後まで通します。見るのは divideFlag と pnList です。

1行ずつ追う 正解の ア(a = maxNum / b = i ÷ j の余り が 0 と等しい)

出典:令和5年度 科目B 公開問題 問1(空欄に ア を入れ、maxNum に 10 を与えたもの)


ループ開始前

集まった素数

▲ いま読んでいる▲ いま書いた

いま計算していること

まだ計算していません

変数の状態

トレース表(進めると1行ずつ積み上がります)

正解は ア

a = maxNum、b = i ÷ j の余り が 0 と等しい。返ってきたのは {2, 3, 5, 7} ── 10 以下の素数がそろっています。

ほかの 3 つは、どこで外れるかがはっきりしています。

イ と エ(b = i ÷ j の商 が 1 と等しくない)は、i が 5 のところで外れます。5 のとき j は 2 だけで、5 ÷ 2 は商が 2、余りが 1 です。商の 2 は 1 と等しくないので、この条件は真 ── 5 は割り切れていないのに divideFlag が倒れ、答えから落ちます。しかもこれは 5 に限りません。内側の for が回るとき j は必ず 2 から始まり、4 以上の数を 2 で割れば商は必ず 2 以上です(2 が 2 つぶん以上入っているからです)。つまり j = 2 の 1 回目で、もう「1 と等しくない」が真になります。結果、maxNum が 3 以上なら、返るのは {2, 3} だけです(2 と 3 は内側が 1 回も回らないので残ります)。

ウ(a = maxNum + 1)は、割り切れるかの判定は正しいのに、調べる対象を 1 つ多く送ります。maxNum が 10 なら 11 まで調べ、11 は素数なので {2, 3, 5, 7, 11} が返ります。11 は「10 以下」ではありません。引数の最小値である maxNum = 2 でも、{2, 3} になって同じように外れます。

次に読む

この問題でどこに手間取ったかで、行き先が変わります。

この記事で引用した資料

いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

シミュレータの動きと、記事の終わりに書いた誤答の返り値は、当サイトで〔プログラム〕を解答群4つとも実際に回して求めたものです。maxNum に 10 を選んだのも当サイトです(原文は maxNum の値を決めていません)。図の中のプログラムは〔プログラム〕からそのまま切り出したもので、①のあいだの行を「……」で省いた以外は変えていません。

Copied title and URL