テスト駆動開発を利用したfibonacciのコード作成 性能向上編
1.概要
前回、再帰呼出しを利用することで、fibonacci関数をTDDで作成しました。再帰呼出しは非常に便利な手法ですが、計算量により実用に適しない場合があります。その内容を説明した上で、TDD手法でfibonacci関数を再帰呼出しを利用しない方式へ修正することを説明します。
2.詳細
fibonacci数列は、0,1,1,2,3,5,8,13,.....と継続する数列で、先行する2つの数値を足した値が、次の数値になる無限に続く数列です。初期値と次の値は、0と1になっています。前回作成したtestcode(Testfibonacci.py)とcode(fibonacci.py)を利用して修正します。
(1) testcode(TestFibonacci.py)を修正
50番目の項目の試験を記述します。
48番目と49番目の項目を加えると、50番目の項目になります。
この試験項目を追加します。
import unittest
from fibonacci import Fibonacci
class TestFibonacci(unittest.TestCase):
def setUp(self):
self.obj = Fibonacci()
def tearDown(self):
del self.obj
def testFibonacci01(self):
assert(self.obj.fibonacci(0) == 0)
assert(self.obj.fibonacci(1) == 1)
assert(self.obj.fibonacci(2) == \
self.obj.fibonacci(0) + self.obj.fibonacci(1))
assert(self.obj.fibonacci(10) == \
self.obj.fibonacci(8) + self.obj.fibonacci(9))
assert(self.obj.fibonacci(50) == \
self.obj.fibonacci(48) + self.obj.fibonacci(49))
if __name__ == '__main__':
unittest.main()
(2) testcode(TestFibonacci.py)を実行
python3 TestFibonacci.py
実行すると処理が終わりません。しばらく経過しても何も変わりません。
そこで、Ctrl-Cで終了します。
理由は以下の通りです。
fibonacci(50) = fibonacci(48) + fibonacci(49)
この式は以下の計算が必要です
fibonacci(48) = fibonacci(46) + fibonacci(47)
fibonacci(49) = fibonacci(47) + fibonacci(48)
更にこの式は以下の計算が必要です
fibonacci(46) = fibonacci(44) + fibonacci(45)
fibonacci(47) = fibonacci(45) + fibonacci(46)
fibonacci(47) = fibonacci(45) + fibonacci(46)
fibonacci(48) = fibonacci(46) + fibonacci(47)
この計算をfibonacci(0), fibonacci(1)になるまで実施する必要があり、計算量が非常に多くなります。つまり、再帰呼出しがボトルネックです。
そこで、fibonacci(N)に対して、fibolist = [0,1,1,2,3,......]とN個のlistを作成するように変えます
(3) code(finonacci.py)を修正
初期値と次の項目を処理するコードに変更します。
class Fibonacci:
def fibonacci(self, number):
fibolist = [0,1]
return fibolist[number]
if __name__ == '__main__':
obj = Fibonacci()
(4) testcode(TestFibonacci.py)を実行
python3 TestFibonacci.py
fibonacci(2)でエラーになります。
RROR: testFibonacci01 (__main__.TestFibonacci)
----------------------------------------------------------------------
Traceback (most recent call last):
File "TestFibonacci.py", line 15, in testFibonacci01
assert(self.obj.fibonacci(2) == \
File "/home/nakasima/mycode/fibotest/fibonacci.py", line 11, in fibonacci
return fibolist[number]
IndexError: list index out of range
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
(5) code(finonacci.py)を修正
3番目以降をfibolistに追加するロジックを追加します。
class Fibonacci:
def fibonacci(self, number):
fibolist = [0,1]
for i in range(2, number+1):
fibolist.append(fibolist[i-2] + fibolist[i-1])
return fibolist[number]
if __name__ == '__main__':
obj = Fibonacci()
(6) testcode(TestFibonacci.py)を実行
python3 TestFibonacci.py
エラーがなくなります
Ran 1 test in 0.000s
OK
これで、fibonacci関数プログラムを再帰呼出しを利用せずにfibonacci.pyが完成しました。
参考
テスト駆動開発入門 ケント・ベック著
コメント
コメントを投稿