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

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

f:id:kirintt:20170914223122p:plain
ねねっちのこと、嫌いにならないでくれ…(9話を観て)。

nagoyanofes.hatenadiary.jp

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

Python 2.7.13を使用しています。

 

 

サンプルプログラム

1か月分のカレンダーを表示するプログラム(引用元:Pythonによるプログラミング入門, p. 13)。

# coding: shift-jis
wday=("sun","mon","tue","wed","thu","fri","sat")
def cal0(n,m):
    # cal0(n,m) は 1 つの月のカレンダーを作成する。
    # n は月の開始日の曜日を表す数字 (0 から 6) であり、
    # 0 は日曜日を意味する。
    # m はその月の日数である。例えば 1 月は m=31 である。
    # 従って 2000 年 1 月のカレンダーは cal0(6,31) で表示される。
    for x in wday: print " ",x,
    print
    for x in range(0, n): print " ---",
    for x in range(1, m+1):
        print "%5d"%x,
        if (x+n)%7==0 : print
    print
cal0(6,31)

プログラムの詳細が知りたい人は有澤先生のテキストを読んでね。

今日のキーワード

閏年の判定

閏(うるう)年については以下を参照。
d.hatena.ne.jp
www.nao.ac.jp


例10)

西暦年号を与えてその年が閏年であれば 1 を、閏年でなければ 0 を返す関数を定義しなさい。(この関数の名前を leap としましょう。英語では閏年の事を leap year と言います) そして、その関数が正しく働いていることを 1996 年、1999 年、1900 年、2000 年 の 4 つの年について確認しなさい。
(引用元:Pythonによるプログラミング入門, p. 31)

プログラム(譜 3.9)

def leap(x):
    if x%400 == 0: return 1
    if x%100 == 0: return 0
    if x%4 == 0: return 1
    return 0
print 1996, leap(1996)
print 1999, leap(1999)
print 1900, leap(1900)
print 2000, leap(2000)

(引用元:Pythonによるプログラミング入門, p. 31)

結果

1996 1
1999 0
1900 0
2000 1

閏年は次の規則で判定される:
a. 4 で割り切れる年は閏年である。
b. 100 で割り切れる年は閏年でない。
c. 400 で割り切れる年は閏年である。
判定の優先順位は c, b, a の順である。
(引用元:Pythonによるプログラミング入門, p. 31)

  • 関数の名前はアルファベットと数字からなる。
  • 関数名の頭文字は必ずアルファベット。
  • 以上は変数の名前についても同じ。
  • 関数leapでは、 if x%400 == 0: return 1 において、xが400で割り切れるとき return 1 が実行される。
  • このとき、leap中の残りの if x%100 == 0: return 0 などは実行されない。
  • if x%400 == 0: return 1 において、xが400で割り切れないとき、次の行の if x%100 == 0: return 0 が実行される(以下同様)。
  • print 1996, leap(1996) と書くことで、結果が何年のものか一目でわかる。
問1

譜 3.9 では 4 で割り切れない場合の判定が最後に回されている。閏年でないケースが大半なのだからこの判定を最初に行う方が実行効率が良いと考えられる。この考えのもとにプログラム 3 の関数 leap(x) を書き直してみなさい。
注: この問題は難しい。そのような難しいプログラムの書き方を推奨しているのではない。
(引用元:Pythonによるプログラミング入門, p. 33)  

プログラム

def leap(x):
    if x%4 == 0:
        if x%100 == 0:
            if x%400 != 0:
                return 0
        return 1
    return 0
print 1996, leap(1996)
print 1999, leap(1999)
print 1900, leap(1900)
print 2000, leap(2000)

結果

1996 1
1999 0
1900 0
2000 1
  • 自分なりに短くしたつもり。
  • if の中に if が入るだけでややこしさが増したように感じる。
問2

現在の暦 (グレゴリオ暦) は 1582 年 10 月 15 日から開始された。つまり、現在の閏年の規則はこの時に制定された。この日は何曜日かを求めよ。(プログラムで解く事を要求していない)
ヒント: グレゴリオ暦は 1 年を 365 . 2425( = 365 + 1 / 4 − 1 / 100 + 1 / 400) 日と定義したことになる。従って 400 年間で [ ] 日になり、この日数は丁度 7 で割り切れる。従って 1600 年のカレンダーは 2000 年のカレンダーと同じである。
(引用元:Pythonによるプログラミング入門, p. 33)

プログラム

y = 365+1.0/4-1.0/100+1.0/400
print "y", y
print "400*y", 400*y
print "400*y%7", 400*y%7

結果

y 365.2425
400*y 146097.0
400*y%7 0.0
  • ヒントに書かれたことを確かめるためのプログラム。
  • 結果を見ると、確かに400年は7で割り切れた。
  • よって、1年目と401年目の曜日は同じであることがわかった。
  • これより、1952年10月15日の曜日は400年後の1982年10月15日と同じであるとわかる。
  • 1982年10月15日は金曜日である(windowsのカレンダー機能より)。
  • したがって、1952年10月15日は金曜日である。

f:id:kirintt:20170914211807p:plain

問3

閏年を判定する関数 leap(x) を if 文を使わないで書くことが可能であると言えば驚きではないだろうか?
ヒント: 西暦 x 年までに発生した閏年の回数と x − 1 年までに発生した閏年の回数の差を計算します。(差だけが問題なので、グレゴリオ暦が実際にいつから始まったかを気にする必要はありません)
(引用元:Pythonによるプログラミング入門, p. 33)

  • 全くわからん!
  • x年までに発生したうるう年の回数ってどう計算するんだ?

今日のミス

閏年の判定

問1

ミスしたけど、そのプログラムに上書きしちゃったからどんなミスだったかわからない。てへぺろ
ちゃんと失敗したものは失敗したものとして記録に残しておくよう気を付けよう。


以上。
問3手も足も出なかったけど、答えがないのよね…オラモヤモヤすっぞ!