「情報関係基礎」過去問を教材化する:2010年 漢数字で数を表す・・あれれ?
大学入試センター試験「情報関係基礎」2010年度の第3問。漢数字で数を表す問題である。これを教材化することを考えたのだが・・・・
2010年度の問題は,大学入試センターのページにはすでにない。このページが続いていれば入手できる。
=========================
正の整数値を漢数字で表示する手順を考えよう。たとえば,次の表のように漢数字で表す。

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

正解は,アから順に 0,5,3,4 これは難しくないだろう。
次にプログラム。まず,次の配列を用意する。

リストの形で書くと
Suji = ["", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["", "十", "百", "千"]
だ。ここで,Suji の第1要素(センター試験の疑似言語は,インデックスは1から始まる)が "一" ではなく,空になっていることに注意。これがあとで意味を持ってくる。KuraiMoji の方は,一の位を表す文字はないので空。
※これにならって,Pythonでのリストを用意した。Pythonのリストはインデックスが0スタートなので,第0要素は空にしておく。要素番号と,数字が同じになるようにするためだ。
Suji = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
KuraiMoji = ["","","十","百","千"]
ここで,Suji の第1要素に "一" を入れている。繰り返しになるがこの違いがあとで意味を持つ。
次がコード。÷は商の整数部分を得る演算子。%は剰余。

あれ?問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ネストが浅くなり構造がわかりやすくなる。実習するならこちらで,設問は適宜設定すればよい。
