ケーキ同好会でも、プログラミングは必須スキルです! 作:蒼(DPD)
月曜日の授業も終わり、部室の椅子に座って一休みする。
先輩方は、月曜日は授業が1時間多いから、今は私一人だけ。
部室の鍵を開けてから先輩方が来るまでの、この一人の時間けっこう好きかも。
さてと、また自習タイムでもしようかな。Pythonの教科書をとってくる。
私がこの分厚い本を持ち歩いているのを知って、ひまり先輩が自分の分を持ってきて部室においてくれた。
だから毎日の登校が少し楽になった。ありがとう、ひまり先輩。
前回やったのはfor文だったから、次のページからだね。
今回はwhile文についてらしい。
i = 0
while i < 10:
print(i)
i += 1
とりあえず、実行してみる。
>python main.py
1
2
3
4
5
6
7
8
9
ふむふむ。
$\texttt{print()}$が変数$\texttt{i}$の中身を表示してるから、$\texttt{i}$は0から9まで増えていくってことか。
......なんかこれ、for文と同じじゃない?whileって英語でも確か、「~の間」って意味だったよね。
わざわざこの文法を覚えなくても、for文でいいんじゃないかな。Pythonを作った人はなんでこの文法を作ったんだろう。
そう思っていたら、次のページにfor文とwhile文の使い分けについて書いてあった。
えーっと、
「while文は条件が満たされている限り実行され続けるため、繰り返しの回数が決まっていないときに使います。」
らしい。
例えば、現在の数が偶数なら2で割って、奇数なら3倍して1を足す......ということを1になるまで繰り返すプログラムは、while文を使うと簡単に書けるんだって。そんな変なことしたくなるかな?
# n は好きな数字に変更できます。
n = 20
loop = 0
while n != 1:
loop += 1
print(n)
if n % 2 == 0:
print(n, "は偶数なので2で割ります。")
n = n // 2
else:
print(n, "は奇数なので3をかけて1を足します。")
n = n * 3 + 1
print(n)
print("ループ回数:", loop)
実行してみる。
>python main.py
20
20 は偶数なので2で割ります。
10
10 は偶数なので2で割ります。
5
5 は奇数なので3をかけて1を足します。
16
16 は偶数なので2で割ります。
8
8 は偶数なので2で割ります。
4
4 は偶数なので2で割ります。
2
2 は偶数なので2で割ります。
1
ループ回数: 7
確かに、これはfor文で書けないね。1になるまでの回数は20とか140とか数によって違うもんね。
へえー、なるほど。そうなると、for文とwhile文は使い分けが大事になってきそう。
ただ繰り返すといっても、状況によってどちらかを選択しないといけないから。
感心していると、哀先輩が部室に入ってきた。
「お、ゆいちゃん何してるの?」
「while文を頑張ってたところです」
「へえ、いいね」
哀先輩が後ろから私のパソコンを覗き込んできた。ふむふむ。とか言っててちょっと緊張する。
「このサンプルプログラムは、コラッツ予想と関係している」
「コラッツ予想!......って何ですか?」
なんかすごそうな名前だね。
「「任意の正整数$N$に対して、$N$が偶数なら2で割り、奇数なら3倍して1を足すということを繰り返すと、どこかで必ず1に到達するだろう」という数学の未解決問題」
「任意の?っていうのは?」
「どんなものでもって意味」
コラッツ予想のやってることを考えてみると、この教科書に書いてあるプログラムとおんなじことをしてるんだね。ただのwhile文の練習じゃないんだ。
「例として$N=20$を選ぶと、さっきの実行結果通りに変化をしていって最終的に1になる」
つまり、このプログラムは本当にループの回数が最初から分からないんだね。for文で書けたら大発見だ。
「じゃあ、このプログラムの$\texttt{n}$を変えていって、ループが終わらないものがあったら大発見ってことですか!」
「そうだね。でもそれはさすがに既に行われてる」
「ですよね......」
がっくり。うなだれてると、哀先輩が私の頭を撫でてくれた。
「でも、先人が通った道を辿るのは決して悪いことじゃない」
「例えば、$N = 27$としてみよう。これは、コラッツ予想の代表的なケース」
>python main.py
27
27 は奇数なので3をかけて1を足します。
82
82 は偶数なので2で割ります。
41
41 は奇数なので3をかけて1を足します。
124
124 は偶数なので2で割ります。
62
62 は偶数なので2で割ります。
31
︙
あれ、ぜんぜん終わらない.......。
︙
16
16 は偶数なので2で割ります。
8
8 は偶数なので2で割ります。
4
4 は偶数なので2で割ります。
2
2 は偶数なので2で割ります。
1
ループ回数: 111
長っ!ループ回数111回だって。驚いていると、哀先輩が私の顔を見てにやりとした。
「このように、小さな整数でも比較的多い回数の操作が必要なものもある」
「へえー」
27みたいな小さな数から始めて111回もかかるなら、ある数が何回で1になるかって全然予想できないね。
「他にも、奇数の場合に3倍してから1を足していたけど、この足す数を3に変えてみよう」
n = 48
loop = 0
while n != 1:
loop += 1
print(n)
if n % 2 == 0:
print(n, "は偶数なので2で割ります。")
n = n // 2
else:
print(n, "は奇数なので3をかけて3を足します。")
n = n * 3 + 3
print(n)
print("ループ回数:", loop)
>python main.py
48
48 は偶数なので2で割ります。
24
24 は偶数なので2で割ります。
12
12 は偶数なので2で割ります。
6
6 は偶数なので2で割ります。
3
3 は奇数なので3をかけて3を足します。
12
12 は偶数なので2で割ります。
6
6 は偶数なので2で割ります。
3
3 は奇数なので3をかけて3を足します。
12
︙
およよ、
\[12 \xrightarrow{\div 2} 6 \xrightarrow{\div 2} 3 \xrightarrow{\times3 + 3} 12\]
を何回も繰り返してプログラムが止まらない!
足す数が3だった場合は、最終的に全部1になるわけじゃないんだ!
「でも、終了条件を1または3になるまでに変えるとどうなるかな」
n = 48
loop = 0
# n != 3 を追加した
while n != 1 and n != 3:
loop += 1
print(n)
if n % 2 == 0:
print(n, "は偶数なので2で割ります。")
n = n // 2
else:
print(n, "は奇数なので3をかけて3を足します。")
n = n * 3 + 3
print(n)
print("ループ回数:", loop)
>python main.py
48
48 は偶数なので2で割ります。
24
24 は偶数なので2で割ります。
12
12 は偶数なので2で割ります。
6
6 は偶数なので2で割ります。
3
ループ回数: 11
さっきと同じ数48から始めてるのに、今回はプログラムが止まった。
へえー不思議だね。
「じゃあ、ゆいちゃん。
この変形したコラッツ予想はすべての自然数で成り立つと思う?」
つまり、偶数なら2で割る、奇数なら3倍して3を足す、という操作を繰り返していくと、
どんな数でも1か3になるかってこと?
え、どうやって考えたらいいんだろう。
私の頭から煙が出ているのが見えたのか、哀先輩が笑っている。
「まあ、これが分かるなら元のコラッツ予想も解けちゃうね。
プログラムを書いてみて正しそうかだけ確かめてみよう」
n = 20
maxloop = 0
for i in range(1,10**7):
loop = 0
n = i
if i % 10**6 == 0:
print(i)
while n != 1 and n != 3:
loop += 1
if n % 2 == 0:
n = n // 2
else:
n = n * 3 + 3
if loop > maxloop:
maxloop = loop
print("最大ループ回数:", maxloop)
「スタートする数字を$1$から$10^7$、つまり1000万の前までfor文でまとめて試してみるよ」
>python main.py
あれ、何も出力されない。ということは、無限ループになってるってことだから、この変形したコラッツ予想は成り立たないってことかな。
「哀先輩、この予想は成り立たないんですね」
「いや、今最初の行が表示されたよ」
>python main.py
1000000
「1から$10^7$までの各整数に対して操作を行うから、結構時間がかかる」
「この1000000って表示されてるのはどういう意味ですか?」
「時間がかかりそうだったから、計算が10%終わるごとに表示されていくようにしている」
しばらく待っていると、少しづつ数が表示されていく。
>python main.py
1000000
2000000
3000000
4000000
5000000
6000000
7000000
8000000
9000000
最大ループ回数: 598
「最後まで実行されました!」
「ということは、変形したコラッツ予想は正しそう、か」
哀先輩の話面白かったな。3倍した後の数を変えたり、最後にする数を増やしたりして自分で新しい問題を作ってもいいんだね。
あ、奇数のときに足す数が3のときどんな数でも1か3になるかもしれないなら、もしかしたら奇数のときに3倍して5を足すようにしたら、どんな数でも1,3,5のどれかになるかも!
問題の証明はできなくてもこうやって遊べるんだ!
予想を立てて、それをプログラムで確かめてみるって面白いね。