4. 制御構造と関数・オブジェクト

ここでは if による条件分岐, forwhile による反復処理,さらには関数の基本的な使い方や,オブジェクトの基本についても学ぼう.

4.1. 条件分岐( if )

Pythonでも基本的な考え方は他の多くのプログラミング言語と同じで,なんらかの値の真偽に応じて処理の流れを分岐する.例えば status という変数の真偽に応じて処理を分岐するには

1>>> status = True
2>>>
3>>> # ifによる分岐
4>>> if status:
5...     print('status is True')  # インデントが1段下がる
6... else:
7...     print('status is False') # ここも1段下がる
8status is True

のように記述すればよい.ここでインデントが構文ブロックの区切りであったことを思い出して欲しい. if に限らず至るところでインデントが必要になるので注意しよう.

なお else 節は必要なければ省略することが可能である.CやFortranと異なり,条件式の部分にカッコが必要ないことに注意しよう.(ただしカッコがあっても文法的には誤りではない.)さらに, if を入れ子にするなどのより細かい制御の例として以下を見てみよう.

 1>>> # 入れ子にするなどより細かい制御
 2>>> a = 1
 3>>> b = 2
 4>>> c = 3
 5>>>
 6>>> if a:
 7...     print('a = ', a)
 8...     # ifを入れ子にする
 9...     if a + b > c:
10...         print('a + b > c')
11...     elif a + b < c:
12...         print('a + b < c')
13...     elif a + b == c:
14...         # さらに入れ子にする
15...         if c >= 0:
16...             print('a + b = c and c >= 0')
17...         else:
18...             print('a + b = c and c <  0')
19...     else:
20...         # passを使って「何もしない」ことを明示することもできる
21...         pass
22>>> # トップレベルのifに対応するelseは省略
23a =  1
24a + b = c and c >= 0

なお21行目の pass は「何もしない」という意味の文である. else 節は省略できるので,わざわざここに pass は使う必要はないのだが,場合によっては「何もしない」ことを明示しておくことでプログラムが理解しやすくなることもある.

ここで分岐に使う条件式についてもコメントしておこう.Fortranでは条件式は真偽値(logical 型の変数,または .true..false. のいずれか)に限られていた.それに対して,Pythonの場合はCに近くなっている.すなわち,Python組み込みのbool型である TrueFalse (これらはPythonの予約済みキーワードで大文字小文字は区別される)だけでなく,任意の型の変数を使うことが出来る.詳細は省くが,とりあえずはCと同様に整数型では 0 が偽とみなされ,それ以外は真とみなされるとおぼえておけばよいだろう.また複雑な条件判定には論理演算子である andornot を組合わせることになる.以下のテーブルには条件判定によく使われる演算子およびその組み合わせの代表的な例を示す.なお,PythonはCやFortranよりも演算子が多い(例えば is 演算子)のだが,ここではそれには触れないことにする.

論理演算子

Python

C

Fortran

A > B

A > B

A > B

A >= B

A >= B

A >= B

A < B

A < B

A < B

A <= B

A <= B

A <= B

A == B

A == B

A == B

A != B

A != B

A /= B

A > B and A > C

A > B && A > C

A > B .and. A > C

A > B or A > C

A > B || A > C

A > B .or. A > C

not A > B

! (A > B)

.not. A > B

以下は論理演算子を使って様々な条件を組み合わせた例である.演算子の組み合わせにはあらかじめ決められた優先順位に応じて順次評価されるが,カッコで明示的に示したほうが分かりやすい.

 1>>> if a < b and a < c:
 2...     print('a is smaller than both b and c')
 3a is smaller than both b and c
 4
 5>>> if a < b or a < c:
 6...     print('a is smaller than either b or c')
 7a is smaller than either b or c
 8
 9>>> if (a == 1 and a + b == c) or not (a == 1 and b == 2 and c == 3):
10...     print('example of complex conditional')
11example of complex conditional

ちなみにPythonにはCの switch ,Fortranの select に対応する構文は存在しないので, ifelif で地道に条件判定をつないでいくことになる.

4.2. 反復処理( for )

Pythonにおける反復処理(ループ)の最も基本的な形は以下のようなものである.

これを実行すると0, 1, 2, 3, 4が順に出力される.もう少し細かい制御をするのであれば

1>>> for i in range(5):
2...     print(i)
30
41
52
63
74
1for i in range(start, stop, increment):
2    print(i)

のようになる.これによって,ループ変数 ii = start から increment ずつ変化しながら i < stop を満たす限りループの中身が実行さる.ここで startstopincrement は全て整数(または整数型の変数)である必要がある.

これはCなら

1for(int i=start; i < stop ;increment++) {
2  printf(i);
3}

Fortranなら

1do i = start, stop-1, increment
2  print *, i
3end do

に対応する.なお range(5) のように1つしか数値を与えなかった場合は,与えられた数値は上記の stop と解釈され, start = 0, increment = 1 が指定されたものとみなす.明示的にこれらを指定した例を以下に示しておこう.

1>>> for i in range(0, 5, 2):
2...     print('i     = ', i)
3...     print('i + 1 = ', i+1)
4i     =  0
5i + 1 =  1
6i     =  2
7i + 1 =  3
8i     =  4
9i + 1 =  5

このようにPythonの for ループはCのそれと非常に似通っており,またFortranの do ループとも細かい違いを除けば同じように使うことが出来るので,まずはこの使い方が理解できていれば問題ない [1]

当然ながら,以下のように入れ子にすることで多重ループにすることも可能である.

 1>>> for i in range(1, 3):
 2...     for j in range(1, 5):
 3...         print('i = ', i, ', j = ', j, ', i*j = ', i*j)
 4i =  1 , j =  1 , i*j =  1
 5i =  1 , j =  2 , i*j =  2
 6i =  1 , j =  3 , i*j =  3
 7i =  1 , j =  4 , i*j =  4
 8i =  2 , j =  1 , i*j =  2
 9i =  2 , j =  2 , i*j =  4
10i =  2 , j =  3 , i*j =  6
11i =  2 , j =  4 , i*j =  8

もう少し実用的な例としてテイラー展開の公式を用いて \(\sin(x)\) の近似値を求める例を考えよう.

 1>>> import math
 2>>>
 3>>> x = 0.2
 4>>>
 5>>> print('*** Taylor expansion of sin(x) ***')
 6>>>
 7>>> y = x
 8>>> a = x
 9>>> i = 1
10>>> print('x = ', x)
11>>> print('i = ', i, ' --- sin(x) = ', y)
12>>>
13>>> for i in range(3, 10, 2):
14...     a = -a / ((i-1)*i) * x**2
15...     y = y + a
16...     print('i = ', i, ' --- sin(x) = ', y)
17>>>
18>>> print('exact   --- sin(x) = ', math.sin(x))
19*** Taylor expansion of sin(x) ***
20x =  0.2
21i =  1  --- sin(x) =  0.2
22i =  3  --- sin(x) =  0.19866666666666669
23i =  5  --- sin(x) =  0.19866933333333336
24i =  7  --- sin(x) =  0.19866933079365082
25i =  9  --- sin(x) =  0.19866933079506174
26exact   --- sin(x) =  0.19866933079506122

4.3. 反復処理( while )

while を使って for の場合と同様に0, 1, 2, 3, 4を出力するループは以下のように書くことができる.

1>>> i = 0
2>>> while i < 5:
3...     print(i)
4...     i += 1
50
61
72
83
94

ただし i += 1i = i + 1 と同じ,また i -= 1 であれば i = i - 1 と同じ意味である.これらの文法はCと同じであるがFortranにはない書き方である.(ただしインクリメント演算子 ++ やデクリメント演算子 -- はPythonには存在しない.)

この例では for と基本的に同じ動作をするものであるが, while はループの終了判定に任意の条件式を用いることができるため,あらかじめ回数の決まっていないループの実行など,より細かい制御を行うことができる.例えば変数 x の値が十分小さくなるまで反復計算をするには

1>>> x = 1.0
2>>> while abs(x) > 1.0e-10:
3...    print('x is not small enough')
4...    # xがゼロに近づくまで何かの計算をする

のような処理を行なうことになる.この例もCなら

1double x = 1.0;
2while( abs(x) > 1.0e-10 ) {
3  // 何かの計算
4}

Fortranなら

1real(8) :: x = 1.0
2do while( x > 1.0e-10 )
3  ! 何かの計算
4end do

以下はテイラー展開の公式を持ちいて, \(\sin(x)\) の値が組み込み関数で求められる値(真の値)に十分近づくまで反復計算をする例である.

 1>>> import math
 2>>>
 3>>> x = 0.2
 4>>> i = 1
 5>>> y = x
 6>>> a = x
 7>>> ytrue = math.sin(x)
 8>>> print('i = ', i, ' --- sin(x) = ', y)
 9>>>
10>>> while abs((ytrue - y)/ytrue) > 1.0e-10:
11...     i += 2
12...     a = -a / ((i-1)*i) * x**2
13...     y = y + a
14...     print('i = ', i, ' --- sin(x) = ', y)
15>>>
16>>> print('approximated = ', y)
17>>> print('exact        = ', ytrue)
18>>> print('rel. error   = ', abs((ytrue-y)/ytrue))
19i =  1  --- sin(x) =  0.2
20i =  3  --- sin(x) =  0.19866666666666669
21i =  5  --- sin(x) =  0.19866933333333336
22i =  7  --- sin(x) =  0.19866933079365082
23approximated =  0.19866933079365082
24exact        =  0.19866933079506122
25rel. error   =  7.0992315183418576e-12

このような場合は繰り返しの回数が事前には分からないので, for を使うよりも while を使う方が素直に処理を記述することができる.

4.4. 複雑な反復処理

forwhile のいずれも continuebreak で,より細かいループの制御を行なうことができる [2].使い方はCのそれと同じである.Fortranでは continuecyclebreakexit と同じ意味である.

以下の例は condition1 が満たされたときに「処理1」を, condition2 が満たされたときに「処理2」を,どちらも満たされなかったときには「処理3」を実行する.

1for i in range(10):
2    if   condition1:
3        # 処理1
4        break
5    elif condition2:
6        # 処理2
7        continue
8    # 処理3

以下の例は while ループで continuebreak を使う例である.

 1>>> i = 1
 2>>> while True:
 3...     i += 1
 4...     if   i%2 == 0:
 5...         print('Multiple of 2 --- ', i)
 6...         continue
 7...     elif i%3 == 0:
 8...         print('Multiple of 3 --- ', i)
 9...         continue
10...     elif i%5 == 0:
11...         print('Multiple of 5 --- ', i)
12...         continue
13...     elif i >= 10:
14...         print('Exit')
15...         break
16...     print('Not a multiple of 2, 3, 5 --- ', i)
17Multiple of 2 ---  2
18Multiple of 3 ---  3
19Multiple of 2 ---  4
20Multiple of 5 ---  5
21Multiple of 2 ---  6
22Not a multiple of 2, 3, 5 ---  7
23Multiple of 2 ---  8
24Multiple of 3 ---  9
25Multiple of 2 ---  10
26Exit

4.5. 関数

複雑でまとまった処理を関数としてあらかじめ定義しておくことで,それを様々な場所から呼び出して使うことができて便利である.関数の詳細にはは触れずに,まずは最も基本的な使い方だけを身につけよう.

4.5.1. 簡単な例

まずは以下の例を見てみよう.

1>>> # 関数定義
2>>> def square(x):
3...     return x**2
4>>>
5>>> # 関数呼び出し
6>>> square(2.0)
74.0

ここで2-3行目が関数の定義である.ここでは与えられた引数の2乗を計算し,その値を返す square という関数を定義している.6行目がこの関数の呼び出しであり,引数の2乗を計算した値が返ってきたのが分かる.

4.5.2. 定義

Pythonにおける関数定義は以下のように def を用いて行えばよい.

1def 関数名(引数1, 引数2, ...):
2    関数内の処理(インデントに注意)

ここでもインデントによって関数定義ブロックとそれ以外を区別していることに注意しよう. def の次の行のインデントが終わるまでが関数定義とみなされる.先ほどの例 square では引数は一つであったが,複数の場合はカンマ , で区切って並べればよい.これらが関数への入力となる [3]

関数の定義位置には注意が必要である.Pythonはコンパイル型の言語ではないため,上から順に実行され,実行時に各行が評価される.したがって, 関数定義は呼び出しよりも必ず前にされていなければならない のである.ただし,これはあくまで実行時の順序であってソースコード上での位置(行数)を意味するものではない.以下の例を見てみよう.

 1>>> # 以下の呼び出しはエラー(この時点ではhelloは定義されていない)
 2>>> #hello1()
 3>>>
 4>>> def hello2(name):
 5...     hello1() # 実行時にhello1が定義済みであればOK
 6...     print('I am', name)
 7>>>
 8>>> # 以下の呼び出しもエラー(この時点ではhello2が呼び出すhello1は定義されていない)
 9>>> #hello2('John')
10>>>
11>>> def hello1():
12...     print('Hello')
13>>>
14>>> hello1()
15>>> hello2('John')
16Hello
17Hello
18I am John

コメントアウトされている2行目の hello1 ,9行目の hello2 の呼び出しはどちらもれエラーとなる.2行目は,この時点で hello1 が定義されていないので明らかである.一方で9行目については,この時点で hello2 が定義されているので一見問題ないように見えるが, hello2 の内部(5行目)で呼び出される hello1 がまだ定義されていないのでエラーになるのである.これはJupyter Notebookを常用しているとセルの評価順序がバラバラになってしまうので曖昧になりやすい点なので注意しておこう.

4.5.3. 返値

関数から呼び出し元に制御を戻すときには return を用いる. return には関数の返値を指定することもできるが,省略することもできる.このときはデフォルトで None を返す [4].なお, return がなくても関数定義ブロックの最後まで到達したときには呼び出し元に制御が戻り, None が返値となる.Fortranでは関数とサブルーチンが区別されているが,Pythonではサブルーチンは存在せず, None を返す関数がFortranのサブルーチンに相当すると考えておけばよいだろう.

4.5.4. 変数のスコープ

関数の中では自由に変数を定義して使うことができる.例えば以下の例をみてみよう.

 1>>> import math
 2>>>
 3>>> # approximation of exp(x) via taylor expansion up to order n
 4>>> def exp_taylor(x, n):
 5...     c = 1.0
 6...     f = 1.0
 7...     for i in range(n):
 8...         c /= (i+1)
 9...         f += c * x**(i+1)
10...     return f
11>>>
12>>> print('--- exp_taylor ---')
13>>> x = 0.5
14>>> print('x     = ', x)
15>>> print('1st   = ', exp_taylor(x, 1))
16>>> print('2nd   = ', exp_taylor(x, 2))
17>>> print('3rd   = ', exp_taylor(x, 3))
18>>> print('4th   = ', exp_taylor(x, 4))
19>>> print('5th   = ', exp_taylor(x, 5))
20>>> print('6th   = ', exp_taylor(x, 6))
21>>> print('7th   = ', exp_taylor(x, 7))
22>>> print('8th   = ', exp_taylor(x, 8))
23>>> print('exact = ', math.exp(x))
24--- exp_taylor ---
25x     =  0.5
261st   =  1.5
272nd   =  1.625
283rd   =  1.6458333333333333
294th   =  1.6484375
305th   =  1.6486979166666667
316th   =  1.6487196180555554
327th   =  1.6487211681547618
338th   =  1.6487212650359622
34exact =  1.6487212707001282

この関数 exp_taylor はテイラー展開の公式を n 次まで用いて exp(x) の近似値を求める.ここで5行目や6行目のように変数を定義して用いている.これらの変数はローカル変数と呼ばれ,この関数の内部でのみ有効な変数である.すなわちこの関数の外で cf という変数は(これとは別に定義しない限り)定義されない.もし関数の外で同じ名前の変数を定義して用いたとしても,それらはこの関数内の変数とは全く無関係である.

一方で,関数の外で定義された変数に関数内からアクセスしたいこともあるかもしれない.例えば,以下の関数 fibonacci は呼ばれるたびにフィボナッチ数列を返す関数である.

 1>>> # global variables for fibonacci
 2>>> a =-1
 3>>> b = 1
 4>>>
 5>>> def fibonacci():
 6...     # a and b refer to the global variables
 7...     global a, b
 8...     c = a + b
 9...     a = b
10...     b = c
11...     return c
12>>>
13>>> print('--- fibonacci ---')
14>>> for i in range(20):
15...     print(fibonacci())
16--- fibonacci ---
170
181
191
202
213
225
238
2413
2521
2634
2755
2889
29144
30233
31377
32610
33987
341597
352584
364181

ここでは ab という変数は関数の外(トップレベル)で定義された変数であり,これらに以前の数列の値を保持している.このような変数をグローバル変数と呼ぶ.関数 fibonacci からこれらの変数にアクセスするには22行目のように global を用いて,グローバル変数を用いることを明示する.この例では a および b は関数内で値が更新されているが,これによってグローバル変数の値も更新される.

このように関数内では基本的に関数内部でのみ有効なローカル変数を用い,グローバル変数へのアクセスが必要なときのみ,それを global によって明示すればよい [5].ただし,グローバル変数は気をつけて使わないとバグの原因となりやすいため推奨できない.引数を使って明示的に値を渡すか,場合によってはクラスを用いて実装する方がよいことが多い.

4.6. オブジェクト

ここまではあえて曖昧にしてきたが,実はPythonでは全て(変数,関数,モジュールなど)がオブジェクト(正確には組み込みの object クラスのインスタンス)である.このことを正確に理解するにはオブジェクト指向の考え方が必要になるので,ここでは詳細には立ち入らない.Pythonはオブジェクト指向についての知識がなくても「なんとなく」使えるという意味で簡単な言語であるが,本格的に使うには,オブジェクト指向やクラス,インスタンス,イテレータなどの少々難解な概念を理解する必要が出てくる.そういう意味ではPythonを本当に使いこなすのは少し難しいかもしれない.Pythonのいいところは初心者でもある程度簡単に使えるのに加えて,上級者には強力な機能を提供しているところと言えるかもしれない.ここではPythonを使うにあたって必要最低限の知識だけを身につけておこう.

4.6.1. 属性

一般にオブジェクトは属性(attribute)と呼ばれるオブジェクトに紐付けられた変数を持つ.例えば「人間」には「名前」という属性があるし,「学生」には「学生証番号」という属性がある,といった具合にそれぞれのオブジェクトの実体が固有の変数を持っていると考えればよい.

オブジェクトに紐付けられた属性にアクセスするには . を用いる.例えば sys というモジュールもオブジェクトなので,いくつかの属性を持っている.以下の例を見てみよう.

1>>> import sys
2>>> sys.version
3'3.7.10 (default, Feb 26 2021, 18:47:35) \n[GCC 7.3.0]'

ここでは sys.versionsys オブジェクトの version という属性にアクセスしている.属性は普通の変数と全く同じように用いることができる.

4.6.2. メソッド

属性が変数であったのに対して,メソッド(method)はオブジェクトに紐付けられた関数と考えればよい.例えば「人間」には「走る」という動作があり,「学生」には「学校に行く」という動作がある.メソッドはこのようなオブジェクトの動きを表すものと考えるとよい.ただし,必ずしもオブジェクトの動きを表すようなメソッドでなくてもよく,単にオブジェクトに紐付けられた関数と考えることも多い.

例えばPythonプログラムを終了するには sys.exit() 関数を使うことは Pythonの基本 で見た通りであるが,これは sys オブジェクトの exit() メソッドを呼び出していると考えればよい.他の例も見てみよう.

1>>> s = 'python'
2>>> s.upper()
3'PYTHON'
4>>> s.lower()
5'python'
6>>> s.capitalize()
7'Python'

この例では文字列 s の メソッド upper()lower()capitalize() をそれぞれ呼び出している.その名前と実行結果から明らかなように,それぞれ大文字に変換,小文字に変換,先頭だけ大文字で以降は小文字に変換した文字列を返す関数である.

4.7. 第4章 演習課題

注釈

以下の課題はJupyter Notebookの使用を前提としているが,もちろん他の実行環境でも同等の処理を実現出来ていれば問題ない.

4.7.1. 課題1

サンプルを実行して動作を確認しよう.

4.7.2. 課題2

2つの整数 m および n を引数として受け取り,その大小を比較する関数 compare

1def compare(m, n):
2    "mとnを比較する"
3    pass

を作成しよう.これを呼び出すと

1>>> compare(2, 1)
22 is larger than 1
3>>> compare(1, 2)
41 is smaller than 2
5>>> compare(3, 3)
63 is equal to 3

などと出力するようにすること.

4.7.3. 課題3

西暦(整数)を引数として受け取り,うるう年かどうか判定する関数 is_leapyear

1def is_leapyear(year):
2    "うるう年の判定"
3    pass

を作成しよう.引数がうるう年であれば真( True ),そうでなければ偽( False )を返すものとする.ただしうるう年の判定条件は以下の通りである.

  • 400で割り切れる年は無条件でうるう年である.

  • 400で割り切れずに100で割り切れる年はうるう年ではない.

  • 100で割り切れずに4で割り切れる年はうるう年である.

以下はこの関数の呼び出しの例である.

1>>> is_leapyear(2000)
2True

4.7.4. 課題4

整数 N を引数として受け取り, \(0^{\circ} \leq \theta \leq 180^{\circ}\) をN分割した点(端点を含むのでN+1点),およびそれらの点における \(\sin \theta\)\(\cos \theta\) の値を出力する関数

1def trigonometric(n):
2    "θ, sinθ, cosθの値を出力する"
3    pass

を作成せよ.これを呼び出すと例えば以下のような出力が得られるものとする.

 1>>> trigonometric(18)
 2  +0.000e+00   +0.000e+00   +1.000e+00
 3  +1.000e+01   +1.736e-01   +9.848e-01
 4  +2.000e+01   +3.420e-01   +9.397e-01
 5  +3.000e+01   +5.000e-01   +8.660e-01
 6  +4.000e+01   +6.428e-01   +7.660e-01
 7  +5.000e+01   +7.660e-01   +6.428e-01
 8  +6.000e+01   +8.660e-01   +5.000e-01
 9  +7.000e+01   +9.397e-01   +3.420e-01
10  +8.000e+01   +9.848e-01   +1.736e-01
11  +9.000e+01   +1.000e+00   +6.123e-17
12  +1.000e+02   +9.848e-01   -1.736e-01
13  +1.100e+02   +9.397e-01   -3.420e-01
14  +1.200e+02   +8.660e-01   -5.000e-01
15  +1.300e+02   +7.660e-01   -6.428e-01
16  +1.400e+02   +6.428e-01   -7.660e-01
17  +1.500e+02   +5.000e-01   -8.660e-01
18  +1.600e+02   +3.420e-01   -9.397e-01
19  +1.700e+02   +1.736e-01   -9.848e-01
20  +1.800e+02   +1.225e-16   -1.000e+00

ここで三角関数 ( math.sin および math.cos )の引数はラジアン単位であることに注意しよう.なお,上の例では出力のフォーマットは

1# xはθ,y1, y2はsinθ,cosθの値
2print('{:+12.3e} {:+12.3e} {:+12.3e}'.format(x, y1, y2))

としている.

4.7.5. 課題5

引数として与えられた2つの整数 m および n の最大公約数を求める関数 gcd

1def gcd(m, n):
2    "mとnの最大公倍数を求める"
3    pass

を作成せよ.これを呼び出すと例えば以下のような出力が得られるものとする.

1>>> gcd(12, 20)
24

なお,最大公約数を求めるには以下のアルゴリズム(ユークリッドの互除法)を用いるとよい.(以下では \(m > n\) を仮定していることに注意しよう)

  1. \(m\)\(n\) で割った余り \(r\) を求める.

  2. もし \(r = 0\) ならば \(n\) が最大公約数である.

  3. もし \(r \neq 0\) ならば, \(m\)\(n\) を, \(n\)\(r\) を代入して[1]に戻る(繰り返す).

4.7.6. 課題6

以下の級数展開

\[e \simeq \sum_{n=0}^{N} \frac{1}{n !}. \quad (0! = 1に注意せよ)\]

により自然対数の底 \(e\) の近似値を求める関数 approx_e

1def approx_e(n, epsilon):
2    "自然対数の底を級数展開を用いて求める"
3    pass

を作成しよう.ただし整数 N および 実数 epsilon を引数として受け取り,関数の返値としては,収束ステータス(収束すれば True そうでなければ False ),反復回数,最終的な近似値の3つを返すこと.

ただし以下の条件を満たすこと.

  • N > 1 でない,または 0 < epsilon < 1 でない場合にはエラーメッセージを表示して,収束ステータス,反復回数,近似値の全てを None とすること.

  • 誤差がepsilon以下になった時点か, n = Nまで計算した時点で級数計算を打ち切る.

以下はこの関数を呼び出し,結果を表示する例である.

 1>>> status, iteration, e = approx_e(10, 1.0e-8)
 2>>>
 3>>> if status:
 4>>>     print('Converged !')
 5>>> else:
 6>>>     print('Did not converge !')
 7>>>
 8>>> print('{:20} : {:>20}'.format('N', iteration))
 9>>> print('{:20} : {:>20.14e}'.format('Approximated', e))
10>>> print('{:20} : {:>20.14e}'.format('Exact', math.e))
11>>> print('{:20} : {:>20.14e}'.format('Error', abs(e-math.e)/math.e))
12Did not converge !
13N                    :                   10
14Approximated         : 2.71828180114638e+00
15Exact                : 2.71828182845905e+00
16Error                : 1.00477663102111e-08

4.7.7. 課題7

与えられた実数 \(a (> 0)\) の平方根の近似値を以下のような逐次近似

\[x_{n+1} = \frac{1}{2} \left( \frac{a}{x_{n}} + x_{n} \right)\]

で計算して返す関数 approx_sqrt

1def approx_sqrt(a, epsilon):
2    "aの平方根の近似値を求める"
3    pass

を作成しよう.ここで epsilon は許容誤差である.

なお, \(x_{n}\)\(\sqrt{a}\)\(n\) 番目の近似値である.初期値としては \(x_{0} = a\) を与え,\(\|x_{n+1} - x_{n}\| < \epsilon \|x_{n}\|\) を満たすまで反復を繰り返せばよい.

以下はこの関数を呼び出し,結果を表示する例である.

1>>> sqrta1 = approx_sqrt(2.0, 1.0e-5)
2>>> sqrta2 = math.sqrt(2.0)
3>>>
4>>> print('{:20} : {:>20.14e}'.format('Approximated', sqrta1))
5>>> print('{:20} : {:>20.14e}'.format('Exact', sqrta2))
6Approximated         : 1.41421356237469e+00
7Exact                : 1.41421356237310e+00