Help us understand the problem. What is going on with this article?

小学生が勉強する算数はこんなにむずかしい

More than 1 year has passed since last update.

おそらくこの記事を読んでいる人は、小学生を経験しているのではないだろうか。
今回は小学生が勉強している足し算の難しさについて取り上げた記事にしたいと思う。

この記事の対象者

取り扱っている漢字が非常に難しいため小学3年生以上を対象にしている。
この記事で用いる数式は10進数を用いているためあらかじめ10進数を知っている者という制限もつけておく。

動作環境

  • python Python 3.6.5

足し算の恐ろしさ

足し算の意味を覚える

数字というのはあくまでも大人たちが都合のいいように定義したもので、1いちと読んで0の次に来る整数であることを覚えることから始まる。
これはなんとpythonというツールを使えば覚える必要は無いようだが、それはあくまでツールを使っているだけであり、0~9までの10個もの数を覚えるなんて相当な労力と言える。
それに加えて足し算を行うには足し算の意味を覚える必要がある。まず足し算の初級編として、11加えたものを考える。これは数式で表す場合は以下のようになる。

1 + 1

当然結果は2であるがこれは前述したように、小学生にとっては「こういうもんだ」と覚える必要がある。つまりpythonで実装すると以下のようになる。

main.py
print("1 + 1 = ")
print("2")

まだ簡単と思う...本当に?
本題はここから始まる...
次に考えるものとしてはおそらく1 + 2なのではないだろうか。つまり考え方としてはこの式が1 + 1なのか1 + 2なのかを判断し、その結果を導くことになる。つまりpythonで実装すると以下のようになる。

main.py
formula = input()
if formula == "1 + 1":
  print("1 + 1 = ")
  print("2")
if formula == "1 + 2":
  print("1 + 2 = ")
  print("3")

ここでこの記事を読んでいる人は第一の恐怖気付くであろう。この途方もなさに...
とりあえず式の第1項を1に固定し、第2項を可変的にするため、input()の対象を第2項のみにて、足す数が1桁のみを考えます。

main.py
print("足す値: ", end="")
second = input()
if second == "0":
  print("1 + 0 = 1")
elif second == "1":
  print("1 + 1 = 2")
elif second == "2":
  print("1 + 2 = 3")
elif second == "3":
  print("1 + 3 = 4")
elif second == "4":
  print("1 + 4 = 5")
elif second == "5":
  print("1 + 5 = 6")
elif second == "6":
  print("1 + 6 = 7")
elif second == "7":
  print("1 + 7 = 8")
elif second == "8":
  print("1 + 8 = 9")
elif second == "9":
  print("1 + 9 = 10")

これで1に対して足す数が1桁の場合を作ることができました。続いてこれを第1項が1桁の0~9までを考えてみるのですが...途方もないですね...
しかも現状まだ1桁同士の足し算しか考えていません。算数の足し算なんて、その組み合わせは無限大であることは明確ですよね。それを全て覚えるなんて不可能と言っても過言では無い。
ここで大人たちは小学生に対し1つの知恵を授ける。それが桁ごとに計算するという方法です。

桁ごとの計算

これは今この記事を書いている自分にとっても非常にありがたい知恵です。これの何がありがたいかというと足し算を各桁で0~9の10個に分けて考えればいいということになります。ここでmainの中が非常に長くなるので関数で作り直しました。

main.py
def one(second):
  if second == "0":
    print("1 + 0 = 1")
  elif second == "1":
    print("1 + 1 = 2")
  elif second == "2":
    print("1 + 2 = 3")
  elif second == "3":
    print("1 + 3 = 4")
  elif second == "4":
    print("1 + 4 = 5")
  elif second == "5":
    print("1 + 5 = 6")
  elif second == "6":
    print("1 + 6 = 7")
  elif second == "7":
    print("1 + 7 = 8")
  elif second == "8":
    print("1 + 8 = 9")
  elif second == "9":
    print("1 + 9 = 10")

print("第2項: ", end="")
second = input()
one(second)

あとは第1項を変更した関数を用意したら完成!...では無いですよね
これでは2桁の足し算ができません。ここで先人たちの新たな知恵!繰り上げを考えます。

繰り上げ

一旦先ほどの関数がみにくいので三項演算子を用いた関数にリファクタリングします。

plus.py
def plus(first, second):
  if first == "0":
    result = ("00" if second == "0" else
              "01" if second == "1" else
              "02" if second == "2" else
              "03" if second == "3" else
              "04" if second == "4" else
              "05" if second == "5" else
              "06" if second == "6" else
              "07" if second == "7" else
              "08" if second == "8" else
              "09")
  return result

全部表示すると長くなるので第一項が0の時のみに表示しました。実際は第一項を0~9まで第二項を0~9まで別ファイルに分けて作っています。なので現状の出力は下のようになります。

terminal
$ python main.py
第1項: 6
第2項: 9
6 + 9 = 15

2桁以上の足し算を実装するために、まず入力された数値をlistに格納し繰り返し関数を呼ぶことで対応します。また、これを実装するにあたり桁数を揃えた方が実装がわかりやすいので、次のように変更します。

main.py
from plus import plus

def output(first, second, result):
  print("{0} + {1} = {2}".format(first, second, result))

print("第1項: ", end="")
first = input()
first_list = list(first)
print("第2項: ", end="")
second = input()
second_list = list(second)

if len(first_list) > len(second_list):
  adjustment = ["0" for i in range(len(first_list) - len(second_list))]
  second_list = adjustment + second_list
elif len(first_list) < len(second_list):
  adjustment = ["0" for i in range(len(second_list) - len(first_list))]
  first_list = adjustment + first_list
else: pass

print(first_list)
print(second_list)

result = []
advance = []
for (f,s) in zip(first_list[::-1], second_list[::-1]):
  digit = plus(f, s)
  advance = advance + [digit[0]]
  result = result + [digit[1]]

output(first, second, "".join(result[::-1]))

現在の実行結果

terminal
-> % python main.py
第1項: 2435
第2項: 234
['2', '4', '3', '5']
['0', '2', '3', '4']
2435 + 234 = 2669

ここで小学生にとっても最難関の繰り上げ処理を実装します。と言ってもpythonを用いているため今あるコードで実装することを考えます。簡単に説明すると繰り上げ用の配列を用意して繰り上げがなくなるまでplus関数にかけてしまいます。

main.py
from student import *

print("第1項: ", end="")
first = input()
first_list = list(first)
print("第2項: ", end="")
second = input()
second_list = list(second)

if len(first_list) > len(second_list):
  adjustment = ["0" for i in range(len(first_list) - len(second_list))]
  second_list = adjustment + second_list
elif len(first_list) < len(second_list):
  adjustment = ["0" for i in range(len(second_list) - len(first_list))]
  first_list = adjustment + first_list
else: pass

half_result, advance = half(first_list, second_list, [], ["0"])
half_result = ["0"] + half_result

while check_advance(advance):
  half_result, advance = half(half_result, advance, [], ["0"])

output(first, second, half_result)

一部を省略したstudent.pyです。

student.py
def output(first, second, result_list):
  result = ""
  flag = False
  for r in result_list:
    if flag or (r != "0"):
      flag = True
      result += r
  print("{0} + {1} = {2}".format(first, second, result))

def half(first_list, second_list, half_result, advance):
  for (f,s) in zip(first_list[::-1], second_list[::-1]):
    digit = plus(f, s)
    advance = [digit[0]] + advance
    half_result = [digit[1]] + half_result
  return (half_result, advance)

def check_advance(advance):
  for a in advance:
    if a == "1":
      return True
  return False
実行結果
第1項: 987
第2項: 876
987 + 876 = 1863

第1項: 999
第2項: 1
999 + 1 = 1000

少し読みにくくなったので関数を別ファイルに移し、コードをスッキリさせました。

はい!これでようやく足し算を実装することができました!
世の中の小学生はこんなに大変な計算を勉強しているなんて、尊敬してしまいますね。

備考

今回の記事では、数値を見て「この場合はこれ!」という判断をそのままコードに置き換えているのでif分岐で対応しています。ありがたいことに「仮に九九のように暗記しているなら」という条件であれば、先に配列に格納して処理すればもっと簡潔に書けるよね!というコメントをいただけました!
やはりプログラミングは十人十色の発想と手法があるので楽しいですね!!!!

今回のソースコードはこちら

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away