見出し画像

「情報関係基礎」過去問を教材化する:2010年 漢数字で数を表す・・あれれ?

大学入試センター試験「情報関係基礎」2010年度の第3問。漢数字で数を表す問題である。これを教材化することを考えたのだが・・・・

2010年度の問題は,大学入試センターのページにはすでにない。このページが続いていれば入手できる。

=========================

正の整数値を漢数字で表示する手順を考えよう。たとえば,次の表のように漢数字で表す。

画像1

問1 これをどのようにして表すかを場合分けして考えた。次の( )に適するものをア〜エの解答群から選びなさい。
 まず,1万未満の数で考える。与えられた数の千の位,百の位,十の位,一の位の順に,一桁ずつ処理をする。
・5023 のように数字が0の桁があるとき,その桁では(ア)
・1211 のように数字が1の桁があるとき,その桁では,一の位ならば「一」を表示する。それ以外の位ならば(イ)
・2345 の各桁のように,数字が2以上の場合,一の位ならば(ウ),
 それ以外の位ならば(エ)。

画像2

正解は,アから順に 0,5,3,4 これは難しくないだろう。

次にプログラム。まず,次の配列を用意する。

画像3

リストの形で書くと
Suji = ["", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["", "十", "百", "千"]
だ。ここで,Suji の第1要素(センター試験の疑似言語は,インデックスは1から始まる)が "一" ではなく,空になっていることに注意。これがあとで意味を持ってくる。KuraiMoji の方は,一の位を表す文字はないので空。

※これにならって,Pythonでのリストを用意した。Pythonのリストはインデックスが0スタートなので,第0要素は空にしておく。要素番号と,数字が同じになるようにするためだ。
Suji = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["","","十","百","千"]
ここで,Suji の第1要素に "一" を入れている。繰り返しになるがこの違いがあとで意味を持つ。

次がコード。÷は商の整数部分を得る演算子。%は剰余。

画像4

あれ?問1でやったアルゴリズムと違うな。

・1211 のように数字が1の桁があるとき,その桁では,一の位ならば「一」を表示する。それ以外の位ならば,位を表す文字のみを表示する。
・2345 の各桁のように,数字が2以上の場合,一の位ならば,その桁の数字のみ,それ以外の位ならば,その桁の数字と位を表す文字を表示する。

なのだから,「もし d≠0 ならば」の中には,ネストした if  が2つあるはず。
まあいいか,ということで,選択肢を見ずにコードを書いた。だいたいいいと思ったら,うまくいかないのがあった。あれ?

さあ,ここから悩んだ。
if のネストが1つということは,問1のアルゴリズムを変形しているわけだ。
キ,クは,数が1以外の場合の「その数と位の文字」としか考えられない。
ならば,オは 1の位が1 と何かの and か。

「あ〜 ややこしい。トシだなあ」と思いつつ,やっと整理し直せた。

値 d が1のとき,
 1の位でなければ位を表す文字のみを書く。
 1の位ならばそのまま"一"を書く。
つまり,「値 d が1かつその桁が1の位でなければ位を表す文字のみを書く」だ。
そうでないとき,
 値dが1でなければ,どの桁でもその数と位の文字を書く。
 値dが1でもその桁が1の位なら,位の文字はもともとないから,その数"一"
 だけを書くことになり,いずれにしても,「数と位の値を書く」でよい。
したがって,オ は d == 1 and keta != 1 カ は KuraiMoji[keta] を表示する だ。
カとクが同じもの「位を表す文字を書く」になるが,まあいいだろう。

Suji = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["", "", "十", "百", "千"]
n = 1121
kurai = 1000
for keta in range(4, 0, -1):
   d = n // kurai
   if d != 0:
       if d == 1 and keta != 1:
           print(KuraiMoji[keta], end="")
       else:
           print(Suji[d], end="")
           print(KuraiMoji[keta], end="")
   n = n % kurai
   kurai = kurai // 10

できた。正しく変換されている。
正解を見る。・・・ あれ?
オ,カが「d=1かつ keta=1」,「"ー"を表示」になっている。Pythonで書くと
      d==1 and keta == 1 :    print("一",  end="") 
だ。それだと,1121 が 一千一百二十ー になっちゃうけど。

さて,問題です。どこがおかしい?

-----------------------------------------------

「間違いじゃないか」と思って,この記事を書き始めて気がついた。

Suji = ["", "二", "三", "四", "五", "六", "七", "八", "九"]

だ。センター試験の配列はインデックスが1から。その第1要素は "一" ではなく "" だ。
これを,筆者は "一" にしていた。

なぜ,問題では,第1要素を空にしたのか。漢数字 "一" を使うのは1の位だけだから,1の位だけ例外処理すればいいので,最初から除いておこう。というわけだ。しかし,そういう説明は書かれておらず,さりげなく Suji[1] ← 「」 と書かれている。ヲイヲイ。

確かに,正解のとおりで正しく表示される。しかし,
 ・漢数字のリストから "一" を除外するのは不自然。
 ・問1のアルゴリズムの構造とコーディングが異なっている。
という点で,問題構成には疑問が残る。まさか「ひねった」わけではないだろう。

・数字が1のとき,その桁では,一の位ならば「一」を表示する。それ以外の位ならば,位を表す文字のみを表示する。
・数字が2以上の場合,一の位ならば,その桁の数字のみ,それ以外の位ならば,その桁の数字と位を表す文字を表示する。

これを

用意した漢数字のリストに"一"はない。だから数字が1でそれが1の位のときだけ例外処理として"一"を表示すればいい

に組み立て直さなければならないのである。

こうして見てくると,このまま教材化するのは生徒には難しいと思われる。素直に,考えた(誘導した)アルゴリズム通りにコーディングできるのが望ましい。

【修正案】

問1 これをどのようにして表すかを場合分けして考えた。次の( )に適するものをア〜エの解答群から選びなさい。
 まず,1万未満の数で考える。与えられた数の千の位,百の位,十の位,一の位の順に,一桁ずつ処理をする。
・5023 のように数字が0の桁があるとき,その桁では(ア)。
・数字が0でないとき,1の位では(イ)表示する。また,十の位より上では,
 数字が1ならば(ウ)表示し,数字が2以上ならば(エ)表示する。

< 選択肢 >
(0) 何も表示しない      (1) 「零」を
(2) その数字のみを漢字で   (3) その桁の位を表す文字のみを
(4) その数字と位を表す文字を (5) 「一」と位を表す文字を

続いてプログラミングのところ(Pythonの場合)

漢数字と位を表す文字を次のようにリストにする。1の位を表す文字はない。また,リストの添え字と数字が一致するように,第0要素はどちらも空にしておく。

Suji = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["", "", "十", "百", "千"]

次は,数 n を漢数字で表すプログラムである。空所にいれるのに最も適当なものを解答群から選びなさい。なお,// は割り算の商の整数部分,% は余りを求めるものである。(空所は生徒の理解状況に応じて設定)

kurai = 1000
for keta in range(4, 0, -1):
    d = n // kurai
    if d != 0:
        if keta == 1 or d >= 2:
            print(Suji[d], end="")
        print(KuraiMoji[keta], end="")
    n = n % kurai
    kurai = kurai // 10

さて,もとの問題には続きがあり,億の数まで漢数字で表すようになっている。これはそのままやってもよいが,for と if のネストがかなり深くなる。

Suji = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["","","十","百","千"]
OkinaKuraiMoji = ["", "", "万", "億"]
x = 51212140649
okinakurai = 100000000
for kugiri in range(3, 0, -1):
   kurai = 1000
   n = x // okinakurai
   if n != 0:
       for keta in range(4, 0, -1):
           d = n // kurai
           if d != 0:
               if keta == 1 or d >= 2:
                   print(Suji[d], end="")
               print(KuraiMoji[keta], end="")
           n = n % kurai
           kurai = kurai // 10
       print(OkinaKuraiMoji[kugiri], end="")
   x = x % okinakurai
   okinakurai = okinakurai // 10000

ここまでネストが深いと,インデントを合わせるのが難しくなる。生徒実習ではやめておくほうがよさそうだ。
こんなときこそ関数の出番だ。

Suji = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["","","十","百","千"]
OkinaKuraiMoji = ["", "", "万", "億"]
def kansuuji(n):
   kurai = 1000
   for keta in range(4, 0, -1):
       d = n // kurai
       if d != 0:
           if keta == 1 or d >= 2:
               print(Suji[d], end="")
           print(KuraiMoji[keta], end="")
       n = n % kurai
       kurai = kurai // 10
   
x = 171652140649
okinakurai = 100000000
for kugiri in range(3, 0, -1):
   n = x // okinakurai
   kansuuji(n)
   print(OkinaKuraiMoji[kugiri], end="")
   x = x % okinakurai
   okinakurai = okinakurai // 10000

ネストが浅くなり構造がわかりやすくなる。実習するならこちらで,設問は適宜設定すればよい。