計算機基礎B - 3. Python の基本事項 (2)

Table of Contents

1 制御構造

1.1 for 文による漸化式の計算

フィボナッチ数列を第20項まで計算するプログラムを考えましょう。 フィボナッチ数列 Fn は次のように定義されます。

F1 = 0
F2 = 1
Fn = Fn-1 + Fn-2    (n >= 3)

これをプログラムにすると次のようになります。

imax = 20
a = 0
b = 1
for i in range(3, imax+1):    # 第3項から第 imax 項まで繰り返し
    c = a + b                 # Fn = Fn-1 + Fn-2 の計算
    print(i, c)
    a, b = b, c               # 次の繰り返しのための準備

for ループに入る前 a は 0 (F1), b は 1 (F2) に設定されます。 したがって,for ループの最初の繰り返しでは c = a + b によって c に F3 が設定されます。 繰り返しブロックの最後の部分 a, b = b, c では a, b がそれぞれ F2, F3 に更新されます。 これにより,次の繰り返しで F4 が計算できるようになります。

練習問題

次の漸化式で定義される数列 An を第10項まで求めるプログラムを作ってみましょう。

A1 = 2
An = 2 * An-1 - 1      (n >= 2)

ヒント: 2項間漸化式なので数列を表す変数は a, b の2つで OK です。

a = 2
for i in range(2, 11):
    b = ここを考える    # 漸化式の計算
    print(i, b)
    ここを考える        # 繰り返しのための準備

1.2 多重ループ

for 文の繰り返しブロックの中に for 文を書くことができます。 こうすることで複数の変数を独立に変化させられます。 次のコードは掛け算九九の表を表示します。

for i in range(1, 10):
    for j in range(1, 10):
        print(i, " * ", j, " = ", i * j)

練習問題

画面に次のように数字を表示するプログラムを作成しましょう。 i 行目に 0 から始まる i 個の数字を改行なしで表示する,と考えるとよいでしょう。

0
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789

ヒント: 整数 i を改行せずに出力するには print(i, end='') を使います。 また,改行だけするには print('') とします。

1.3 while 文による繰り返し

あらかじめ繰り返し回数がわからない場合には while 文を利用します。 while 文は「繰り返しの条件」が成り立っている間 (つまり,条件が True である間) だけブロックを繰り返します。

while 繰り返しの条件:
    繰り返しのブロック

あまり面白くない例ですが,次のコードは 1 から 10 までの整数の和を求めます。

n = 1
tmp = 0
while n <= 10:
    tmp = tmp + n
    n = n + 1
print(tmp)

n が 11 になると繰り返しの条件 n <= 10False になって while 文が終了し print(tmp) が実行されます。

練習問題

キーボードから整数 n を入力し,

  • 偶数なら 2 で割る
  • 奇数なら 1 を加える

という操作を,結果が 1 になるまで繰り返すプログラムを作成しましょう。

n = int(input("Input an integer (> 1): "))
while ここの条件式を考える:
    if n % 2 == 0:
        n = n // 2         # 整数除算
    else:
        n = n + 1
    print(n)

1.4 ループの中断: break と continue

break によるループからの脱出

for 文や while 文の中で break 文を実行すると, それ以降の処理を行わず,繰り返し処理を途中で終了します。 次の例を実行し break の動作を確認しましょう。

for i in range(10):
    if i == 5:
        break
    print(i)

continue によるループの継続

for 文や while 文の中で continue 文を実行すると, それ以降の処理を行わず,ループの先頭に戻って次の繰り返しを始めます。 次の例を実行し continue の動作を確認しましょう。

for i in range(10):
    if i % 3 == 0:
        continue
    print(i)

i が 3 で割り切れるときは continue 文によってそれ以降の処理が省略され,次の繰り返しに移ります。 そのため 3 の倍数は画面に表示されません。

1.5 無限ループ

while 文で繰り返しの条件を True とすると,無限に繰り返すループが作れます。 通常,ループからの脱出条件をチェックして break 文を実行します。

while True:
    :
    if ループからの脱出条件:
        break
    :

さきほどのプログラムは次のように書いたほうがわかりやすいかもしれません。

while True:
    n = int(input("Input an integer (> 1): "))
    if n >= 1:    # 1 以上の整数であれば抜ける
        break

while True:
    if n % 2 == 0:
        n = n // 2
    else:
        n = n + 1
    print(n)
    if n == 1:    # 結果が 1 になったら抜ける
        break

練習問題

「コラッツの予想」とは,任意の正の整数 n に対し

  • n が偶数なら n を 2 で割る
  • n が奇数なら n に 3 をかけて 1 を足す

という操作を繰り返すと,どんな初期値から始めても有限回の操作のうちに必ず 1 に到達する,というものです。 例えば,初期値を 6 にすると

6  3  10  5  16  8  4  2  1

という数列が得られます。 初期値として 27 を選ぶと数列は 111 ステップにまで達します。 キーボードから初期値を入力し,結果が 1 になるまで表示するプログラムを作成しましょう。

n = int(input("Input an integer (> 1): "))
while True:
    if n % 2 == 0:
        n = n // 2
    else:
        n = n * 3 + 1
    以下略

1.6 ニュートン法

無限ループの応用として,Newton 法で正数 a の平方根を求めてみましょう。

ニュートン法の原理

方程式 f(x) = 0 の根は次のように求めることができます。 x0 を根の第1近似とします。 曲線 y = f(x) 上の点 (x0, f(x0)) における接線が x 軸と交わる点を x1 とすると, x1 は x0 よりも f(x) = 0 の根に近い値となります。 第 n 近似 xn が求まったとすると次の近似 xn+1 は次の式で求めることができます。

xn+1 = xn - f(xn) / f'(xn)

これを繰り返すことによって方程式の根を得ることができます。 解の収束(値が一定の値に近づくこと)は xn と xn+1 の差が十分小さくなったかどうかで判定します。 これを Newton 法といいます。 【Wikipedia の説明をみる】

平方根の計算

f(x) = x*x - a とすると f(x) = 0 の根が a の平方根になります。 Newton 法の一般論より

xn+1 = (xn + a / xn) / 2

で作られる数列が √a に収束します。 これをプログラムにすると次のようになります。 abs(x) は x の絶対値を求める関数です。

a = float(input("Input a positive real: "))
xold = a                              # 解の第1近似を a とする
EPS = 1.0e-5                          # 収束判定のための微小定数
while True:                           # 無限ループ
    xnew = (xold + a / xold) / 2.0    # 漸化式の計算
    if abs(xnew - xold) < EPS:        # 解が収束したら break 文で脱出
        break
    xold = xnew                       # 次の繰り返しの準備
print(xnew)

2 本日の課題

2.1 曜日の計算

日曜日を 0,月曜日を 1,…,土曜日を 6 というように各曜日を番号で表わすものとする。 このとき,今日の曜日を表わす番号 i と日数 n を読み込んで, n 日後の曜日の番号 j を求めよ。

i = int(input("i = "))
n = int(input("n = "))
j = ...
print(j)

2.2 階乗 n!

キーボードから 0 以上の整数 n を入力し,n の階乗 n! を求めるプログラムを作成せよ。 階乗 n! は次のように定義される。 0! = 1 も正しく計算できるようにすること。

0! = 1
n! = 1 * 2 * 3 * … * n    (n >= 1)

ヒント: range() の中をどうしたらよいか。

n = int(input("Input n: "))
tmp = 1
for i in range(ここを考える):
    tmp = tmp * i
print(tmp)

2.3 2重階乗 n!!

キーボードから正の整数 n を入力し,n の2重階乗 n!! を求めるプログラムを作成せよ。 2重階乗 n!! は次のように定義される。

n!! = 1 * 3 * 5 * … * n    (n が奇数の場合)
      2 * 4 * 6 * … * n    (n が偶数の場合)

定義をみると n の偶奇で場合分けする必要があるように思えるが,実は不要。 ヒント:減少ループを利用する。

n = int(input("Input a positive integer: "))
tmp = 1
for i in range(ここを工夫する):
    tmp = tmp * i
print(tmp)

2.4 立方根の計算

Newton 法で正数 a の立方根を求めるプログラムを作成せよ。 f(x) = x**3 - a とすると f(x) = 0 の解が立方根を与える。 Newton 法の一般論から,漸化式は

xn+1 = xn - (xn**3 - a) / (3 * xn**2)
     = (2 * xn + a / xn**2) / 3.0

で与えられる。

3 前回の課題の解答

3.1 閏年の判定

400, 100, 4 の順にチェックすると簡単になります。

year = int(input("Input year: "))
if year % 400 == 0:
    print("leap year")
elif year % 100 == 0:
    print("common year")
elif year % 4 == 0:
    print("leap year")
else:
    print("common year")

4, 100, 400 の順にチェックするとこんなに感じ。

if year % 4 == 0:
   if year % 100 == 0:
       if year % 400 == 0:
           print("leap year")
       else:
           print("common year")
   else:
       print("leap year")
else:
   print("common year")

Copyright © 2012-2016 Masahiro Takagi. All right reserved.

Date: 2016-10-24 Mon 20:34

Emacs 25.1.1 (Org mode 8.2.10)

Validate