きっかけなんて些細なモンですよ。

NEW GAME!を観ました。プログラミング始めます。(16)

NEW GAME!! 最後まで良いアニメでした!ありがとう!!
f:id:kirintt:20171005233015p:plain

前回
nagoyanofes.hatenadiary.jp

※基本的に、愛知大学の有澤先生がプログラミングの講義で使用しているテキスト「Pythonによるプログラミング入門」に沿って進めています。
Python 2.7.13を使用しています。

今回からは第4章「プログラムの作り方」を勉強していきます。

大雑把に言えば計算機ができる事はたった次の 4 つである。
1. 計算機はデータを記憶できる。
2. 計算機は簡単な計算ができる。
3. 計算機は簡単な論理判断ができる。
4. 計算機は以上の 3 つを順序立てて実行できる。
(引用元:Pythonによるプログラミング入門, p. 37)

フィボナッチ数列

フィボナッチ数列とは最初に 2 つの数 1 と 1 から出発して残りの数はその前の 2 つの数を足して得られる数列である。
1 1 2 3 5 8 ...
(引用元:Pythonによるプログラミング入門, p. 37)

この節では、フィボナッチ数列を例にプログラムの作り方を説明している。プログラムそのものよりも、それを作るための過程について詳細に学ぶことができると思う。
筆者によると、プログラムは以下のステップを経て完成するという。

1. 必要な変数の個数と各々の役割を定める事
2. その下で計算手順を分析する事
3. 計算手順を計算機言語 (今の場合は Python ) で表現する事
(引用元:Pythonによるプログラミング入門, p. 40)

このうち、アルゴリズムの問題である1と2が難しい部分らしい。ちなみに、3の部分はコーディング(coding)と呼ばれる。

以下、練習問題。問1~3は本文で話題を展開することを目的とした質問の投げかけという感じだったので省略しました。

問4

最大公約数の計算は互除法が効率の良いアルゴリズムとして有名である。この方法によると、6201 と 11349 の最大公約数は以下の様に除算を繰り返して求まる。(右側に計算プロセスを記号的に示す。)
11349 を 6201 で割った剰余を計算して 5148 を得る。 11349%6201 → 5148
6201 を 5148 で割った剰余を計算して 1053 を得る。 6201%5148 → 1053
5148 を 1053 で割った剰余を計算して 936 を得る。 5148%1053 → 936
1053 を 936 で割った剰余を計算して 117 を得る。 1053%936 → 117
936 を 117 で割った剰余を計算して 0 を得る。 936%117 → 0
剰余が 0 になった所で計算を止め、117 を答とする。
この計算法を使用して 5442853 と 4555013 との最大公約数を求めなさい。
(引用元:Pythonによるプログラミング入門, p. 40)

まずテキストに載ってたサンプルを参考に組んでみたやつ。

def gcd(x,y):
    while z > 0:
        z = x%y
        x = y
        y = z
        if z == 0:
            print x
            
gcd(5442853,4555013)

結果:失敗

UnboundLocalError: local variable 'z' referenced before assignment

zを定義しておらず怒られちゃった。直します。

def gcd(x,y):
    z = 100
    while z > 0:
        z = x%y
        x = y
        y = z
        if z == 0:
            print x
            
gcd(5442853,4555013)

結果:成功!

179

今回はz = 0で繰り返しが終了するプログラムだから、開始時点でzに0より大きい値を入れておけばOKということですな。というわけでwhileの前にz = 100を入れることで成功!

問5

最大公約数を返す関数 gcd(x,y) を定義せよ。またその下で以下の計算が正しく行われているか否かを確認せよ。
gcd(11349,6201) , gcd(6201,11349)
また x, y の一方が 0 の時に gcd(x,y) は何を返すべきかを最大公約数の定義に基づいて考えよ。
(引用元:Pythonによるプログラミング入門, p. 40)

まず組んでみたのがこれ。

# coding: shift-jis

def gcd(x,y):
    z = 100
    while z > 0:
        if x == 0:
            print "最大公約数はありません"
        elif y == 0:
            print "最大公約数はありません"
        else:
            z = x%y
            x = y
            y = z
            if z == 0:
                print x

gcd(10,0)

結果:失敗

最大公約数はありません
最大公約数はありません
最大公約数はありません
最大公約数はありません
最大公約数はありません
最大公約数はありません
(ずっと続く)

うわあああああああああああああああああああああ!!
というわけで修正。

# coding: shift-jis

def gcd(x,y):
    z = 100
    while z > 0:
        if x == 0:
            z = 0
            print "最大公約数はありません"
        elif y == 0:
            z = 0
            print "最大公約数はありません"
        else:
            z = x%y
            x = y
            y = z
            if z == 0:
                print x
            
gcd(11349,6201)
gcd(6201,11349)
gcd(10,0)
gcd(0,10)

結果:成功ゥ!

117
117
最大公約数はありません
最大公約数はありません

x=0やy=0の場合に、zはずっと100のままだから何度も「最大公約数はありません」を表示しちゃってたってワケ。それぞれzに0を代入するよう書き加えることでクリア!

問6

家を買う為に、銀行から金利 5% で 3000 万円借りるとせよ。毎年 200 万円ずつ返済する。何年後にこのローンを返せるか? また最後の年にはいくら支払えばよいか?
(引用元:Pythonによるプログラミング入門, p. 40)

一撃で決めてやるぜ…!!

# coding: shift-jis

def loan(k,n,m):
    # 金利:k
    # 借入金額:n
    # 毎年の返済額:m
    # 現在の借金残高(金利込):n0
    # 定額返済後の借金残高:n1
    # 借金を返済するのにかかる年数:year
    n1 = n # 最初の年
    year = 1
    while n1 >= 0:
        year = year + 1
        n0 = int(n1*(1+k)) # int(x)はxを小数点以下切り捨て
        n1 = n0 - m
        if n1 <= 0:
            print "ローン返済にかかる年数:",year,"年"
            print "最後の年に支払う金額:",n0,"円"

loan(0.05,30000000,2000000)

結果:成功ゥゥアアア!!!!!

ローン返済にかかる年数: 30 年
最後の年に支払う金額: 838620

やったぜぇぇえええええ!!!!!!!!!!!
お金の計算なので、小数点以下が表示されないよう考慮しましたァァァ!!(ドドドドヤァッ!!!