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

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

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

#動作環境
- python Python 3.6.5

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

`1 + 1`

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

```python:main.py
print("1 + 1 = ")
print("2")
```

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

```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桁のみを考えます。

```python: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の中が非常に長くなるので関数で作り直しました。

```python: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桁の足し算ができません。ここで先人たちの新たな知恵！繰り上げを考えます。

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

```python: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`まで別ファイルに分けて作っています。なので現状の出力は下のようになります。

```zsh:terminal
$ python main.py
第1項: 6
第2項: 9
6 + 9 = 15
```
2桁以上の足し算を実装するために、まず入力された数値をlistに格納し繰り返し関数を呼ぶことで対応します。また、これを実装するにあたり桁数を揃えた方が実装がわかりやすいので、次のように変更します。

```python: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]))
```
現在の実行結果

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

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

```python: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`です。

```python: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
```

```zsh:実行結果
第1項: 987
第2項: 876
987 + 876 = 1863

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

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

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

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

今回のソースコードは[こちら](https://github.com/TakahiroSono/full-adder.git)