2.2 繰り返し処理

(1/1)
カール・フリードリッヒ・ガウス
カール・フリードリッヒ・ガウス
今回は、1から10までの整数の和を求めるプログラムを作ってみよう。

天才数学者カール・フリードリッヒ・ガウスは、7歳の時、この問題を \( \displaystyle \frac{10 \times(1 + 10)}{2} \) という方法で解いてみせた。
しかし、私たちは凡人である――地道に1から10までを順に足し算していくことにしよう。幸いなことに、Pythonには繰り返し処理という仕組みが用意されており、このような地道な繰り返し処理を簡単に書くことができる。

目次

サンプル・プログラム

1から10までの和

print(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10)
"add10.html" は、1から10までの整数の和、すなわち \[1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 \] の計算結果を表示するプログラムである。

数式をそのままプログラムにしただけだが、目的とする計算結果を正しく表示するから、このプログラムは正しい
しかし、1から100までの整数の和を計算しようとすると、1行がとても長くなってしまう。1行があまりにも長いと、たまたま計算結果が間違っていたときの不具合箇所(バグ)を探すのに時間がかかる
n = 1
n = n + 2
n = n + 3
n = n + 4
n = n + 5
n = n + 6
n = n + 7
n = n + 8
n = n + 9
n = n + 10
print(n)
Googleスプレッドシート:1から10の和を求める
Googleスプレッドシート:1から10の和を求める
そこで、足し算の部分を1行1行に分けたプログラムが "add11.py" である。

こうすればバグは見つけやすくなる。
だが、もし1から100までの整数の和を計算しようとすると、プログラムは100行にもなってしまう。これなら、わざわざプログラムにせずに ExcelやGoogleスプレッドシートでSUM関数を使って計算した方が早いだろう。

for文

# 合計を保存する変数を初期化する.
n = 0
# リストの範囲(1~10)で加算を繰り返す.
for i in range(1, 11):
	n = n + i
# 結果を表示する.
print(n)
多くのプログラミング言語には繰り返し処理という仕組みが用意されている。
"for1.py" は、Pythonに備わっている繰り返し処理の一種である for文を使って1から10までの整数の和を計算するプログラムである。
for文
for文
"add11.py" では10行を要した足し算が、コメント除く実質3行に収まっている。

ここで for文は、リスト range(1, 11) から変数 i に値を1つずつ取りだし、次のインデントで示すブロックを実行するという働きをする。
いずれリストの解説は行うが、ここでは、range型とは引数で指定した整数の数列を生成する働きを持つと覚えておいてほしい。第1引数は開始値、第2引数は終了値+1。ここでは1以上11未満(10以下)の整数の数列を発生する。
range の引数を変えてやれば、計算範囲を自由に変更できる。試してみてほしい。
print(list(range(1, 11)))
range型
range型
実際に range(1, 11) の中に入っている要素をリストアップしたプログラムが "range.py" である。
他の多くのプログラミング言語には for文が備わっているが、Pythonと異なり、繰り返しの初期値と終了条件を変数で指定するものが多い。ここで、終了条件を誤ったり、計算誤差で終了条件を超えて繰り返しを行ってしまうことがある。俗に無限ループと呼ばれる不具合なのだが、特殊な終了条件を入れないと無限ループを再現しないので、テストで見落としやすい不具合である。
一方、Pythonfor文は、リストに入っている要素の数しか繰り返さない。そして、range型は整数しか扱うことができないので、計算誤差が発生することもない。
つまり、Pythonfor文を使っている限り、無限ループに陥ることはまず無いと考えていい。これは Pythonを使う上での大きなアドバンテージだ。

植木算と計算誤差

# 周囲6メートルの池に60cmおきに杭を打つ位置を求める.
for i in range(0, 600, 60):
	print(i)
植木算
"for2.py" は、周囲6メートルの池に60cmおきに杭を打つ位置を求めるプログラムだ。小学校で植木算として習った方も多いだろう。
この問題は、JavaScriptプログラミング入門「1.4 繰り返し処理」のクイズとして取り上げ、
for (let i = 0; i < 6; i = i + 0.6) {
という for文を示した。
ところが、この終了条件で計算誤差が発生し、11本の杭を打つ羽目になってしまう。

一方、Pythonの場合、前述のように range型は整数しか扱うことができないので、否が応でも、長さの単位をcmに合わせなければならず、正しく10本の杭の位置を求めることができる。

練習問題:繰り返し処理

次回予告

次回は、ここで作った1から10までの整数の和を求めるプログラムを、見やすく色分け表示するよう改良する。次に、開始値と終了値をキーボードから入力できるようにする。最後に、入力エラー対策を行う。

コラム:非同期処理と無限ループ

エッシャー「上昇と下降」
エッシャー「上昇と下降」
非同期処理について説明するのは、まだだいぶ先になるが、すでに仕事で Pythonを使っている方は注意してほしいことがある――Python, JavaScript, C#といった非同期処理を扱えるプログラミング言語では、繰り返し処理の中に絶対に非同期処理を入れてはいけない
なぜなら、非同期処理が終わらないうちに次の周回に入ってしまうことがあり、終了条件が正しく働かず、期待した回数を繰り返さなかったり、最悪、無限ループに陥るリスクが高いからだ。これも、実際に値を入れてみないと発生しない類いの不具合なので、テストで見落としやすい。

JavaScriptの場合、Promiseで回避するという手もあるが、これをやると、処理速度が目に見えて遅くなってしまう。
繰り返し処理ではなく再帰呼び出しをするのが第一回避策である。ただし、メモリなどのコンピュータリソースをかなり喰う。
逆に言えば、非同期処理を行うシステムを動かすなら、相応のメモリとCPUを搭載したハードウェアを選択しなければならない。そうしたハードウェアを調達する経済的余裕がないなら、非同期処理が不要なPHPでプログラムを作ることを考えた方がいい。

仕事でプログラムを開発する言語を選ぶのは、こうした経済的な事情によることが多い。けっして気分や得意不得意で選ぶものではない。
(この項おわり)
header