第 5 週の庭いじり 5.1 黄金比 さて、庭いじりも 5 週目に突入だ。地面から思わぬものが出てくるかもしれないよ。 始めにフィボナッチ数列に再登場してもらおう。 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, . . . そして、フィボナッチ数列の 2 項の比 1 2 3 5 8 13 21 34 , , , , , , , , ... 1 1 2 3 5 8 13 21 を計算してみよう。これは Haskell がすぐにやってくれる。以前と同じように、対話モードで関 数を定義して計算させれば十分だ。 (ghci env.) Prelude> let f n = if n > 1 then f (n-1) + f (n-2) else 1 Prelude> [f (n-1) / f (n-2) | n <- [1..20]] [1.0,1.0,2.0,1.5,1.6666666666666667,1.6,1.625,1.6153846153846154,1.6190476 19047619,1.6176470588235294,1.6181818181818182,1.6179775280898876,1.618055 5555555556,1.6180257510729614,1.6180371352785146,1.618032786885246,1.61803 4447821682,1.6180338134001253,1.618034055727554,1.6180339631667064] なんだか乱雑な数が並んでしまったけど、先頭から数個を除けば、どれも 1.6 ほどの値だ。おっ (後の項) と、その前に f (n-1) / f (n-2) の計算は 2 項間における のである。しかし、比なん (前の項) (前の項) (前の項) だから別に で求めたっていいだろうに。 として計算をやり直してもらおう。 (後の項) (後の項) (ghci env.) Prelude> [f (n-2) / f (n-1) | n <- [1..20]] [1.0,1.0,0.5,0.6666666666666666,0.6,0.625,0.6153846153846154,0.61904761904 76191,0.6176470588235294,0.6181818181818182,0.6179775280898876,0.618055555 5555556,0.6180257510729614,0.6180371352785146,0.6180327868852459,0.6180344 478216818,0.6180338134001252,0.6180340557275542,0.6180339631667066,0.61803 39985218034] 1 2 状況は似ているが、今度は先頭から数個を除けば、どれも 0.6 ほどの値だ。よーく見ると、各値 は末尾に多少の違いがあるようだが、最初に計算した比の値と較べて大体 1 の差があるね。この 誤差は Haskell の計算誤差なのか、それとも本当に微妙に差があるのだろうか。実は、正しい比 の値にはまったく誤差はないのだ。この面白い性質を持つ比の値は黄金比と呼ばれている。一般に は、1.618033 · · · の方を黄金比と呼ぶことが多い。 黄金比とは一体どういう数なのだろうか。計算は簡単にできるので確かめてみよう。 まず、1.618033 · · · に収束する真の値を x としよう。あとから求めた比 0.618033 · · · は、x の逆 1 比 のことである。それが x より 1 小さい値に等しいのだから x 1 =x−1 x が成り立つ。等式は簡単な 2 次方程式となる。両辺に x を掛けて整理すると x2 − x − 1 = 0 だか ら、解の公式を使えば一発で解ける。フィボナッチ数の比は正の値なので、x > 0 の解を求めると √ 1+ 5 x= 2 √ であることがわかる。黄金比は無理数 5 を含む数なのだ。庭いじりも 5 週目に入ったので、それ にふさわしい数の登場だ。解は正の数だけに限っているものの、方程式からひとつの解しか得られ ないということは、この性質を満たす数は黄金比だけということである。 1 Haskell でシミュレートしてみよう。ここでは = x − 1 を移項して x 1 x= +1 x (5.1) で x を探ることにする。そのほうが x の値を直接計算できるからだ。ところで、探るという言葉 が気になるね。なぜそのような言葉遣いをしたかはスクリプトを見てもらいたい。 (ghci env.) Prelude> let g n = if n > 1 then 1/g (n-1) + 1 else 1 Prelude> g 20 1.6180339985218035 Prelude> g 100 1.618033988749895 1 + 1 に対応する式を、再帰を用いてちょいと書いただけだ。 x else 節が 1 であることから、初期値として x = 1 が与えられている。g 20 で 20 回程度計算して スクリプトは対話モードで x = も、g 100 で 100 回程度計算しても大差ないようだ。どうやら黄金比に収束するように見える。 さて、スクリプトを見て、あれ? Haskell が 2 次方程式を解くんじゃないんだ、と感じただろ う。そう、コンピュータは計算をする機械であって、問題を解く機械ではない。問題を解く手順は tmt’s math page! 3 人間が与えるのだ。では、この手順は何をしているのだろう。どう見ても 1 = x − 1 と同等な— x つまり両辺に x を掛けた—方程式 1 = x2 − x を解いているのではないね。でも、解である黄金比が求められている。 それなら 1 = x2 − x を移項した式、x = x2 − 1 を使っても同じことだろう。計算式の定義を g n = g n * g n - 1 に変えてみる。*が何と何の掛け算なのかは分かってるね。演算子より関 数の結合の方が優先されるはずだったから、この式は g n = (g n) * (g n) - 1 と同等だよ。さ あ、準備は整った。関数を走らせよう。 (ghci env.) Prelude> let g n = if n > 1 then g (n-1) * g (n-1) - 1 else 1 Prelude> g 20 0 Prelude> g 21 -1 あれ? 0?-1? そりゃ、そうだ。x2 − 1 に 1 を代入して 0、その 0 を代入して −1、その −1 を代入して 0、. . . だからね。else 節がだめなんだ。else 2 ぐらいに直して仕切り直しじゃ。 (ghci env.) Prelude> let g n = if n > 1 then g (n-1) * g (n-1) - 1 else 2 Prelude> g 20 99041466760369954044427685932862489508781487688562513893320343819689510782 53796496171092896204287749283238857037808951820815674642678881510362463739 15636953973312352766372789017153205542513361903279906043122219476004512654 60442883907418839004677997414550293560155508846528321744640901134913334498 28742920504296364941188676495189175254433827715708241914001579564159781655 13207539676495418845280123755859633124041303938610450928325140375461485009 1140543940116958............... うわー、やばっ! だけど落ち着いて。巨大数が表示されても ctrl-c で止まるはずだから。でも g 20 程度なら、おろおろしてる間に最後まで表示してしまうかもしれない。そんなわけで、間違っ ても g 100 なんて試さないように。 どうして? 同じ関係の方程式を使ったはずなのに。その秘密はグラフを描けば見えてくる。は 1 じめのスクリプトに使ったのは x = + 1 で、次のスクリプトに使ったのは x = x2 − 1 だから、 x それぞれ 1 +1 x y=x と y= y=x と y = x2 − 1 4 のグラフの交点を求めていることになる。ただし、スクリプトは一気に交点を求めているのではな い。適当な x から始めて、いわば 2 つのグラフを渡り歩くような処理がスクリプトのしているこ とだ。そういうことなら実際にグラフを描いてみるのがよい。 y O y • x 1 O • 2 x 1 x 軸上の点から始めて、2 つのグラフを縦横縦横. . . 交互に進んでみよう。y = x と y = + 1 の x 1 グラフでは、x = 1、つまり (1, 0) で始まった値が + 1 によって 2、すなわち双曲線上の点 (1, 2) x 1 になる。次は + 1 に x = 2 を代入することになるのだが、その値は x = 2 の位置の双曲線上の x 点を探せばよく、図形的には y = x 上の x = 2 に対応する双曲線上の点である。このようなたど 1 り方は、縦横の移動によって y = + 1 と y = x を渡り歩くことに相当する。すると、その軌跡 x 1 は y = + 1 と y = x の交点に向かって進むことになるだろう。だから、収束している。 x 一方、y = x と y = x2 − 1 のグラフで同じことをすると、(2, 0) で始まった値は、y = x2 − 1 に よって 3、すなわち放物線上の点 (2, 3) になる。次は直線上の (3, 3) を経て放物線上の (3, 8) へ 行く。こうなると、もう誰にも進行を止められない。値は 22 − 1 = 3 → 32 − 1 = 8 → 82 − 1 = 63 → 632 − 1 = 3968 → ··· のように爆発的に大きくなる。これが 20 回の計算のあとで表示された巨大数の正体である。 でも、4 回の計算で 3968 なんだから、あと 16 回の計算であそこまで大きな数になるはずがない と思うかもしれない。3968 ≈ 4 × 103 として、この先の計算を考えてみよう。あと 16 回というのは 16 個 z }| { (· · · (((4 × 103 )2 )2 )2 · · ·)2 ということだ。これは (4 × 103 )2 16 = (4 × 103 )65536 = 465536 × 10196608 だから 10196608 の部分だけでも 20 万桁近い。20 万桁の数ってのは、たとえば 80 桁 25 行の画面で 見たら 100 ページ分だよ。ひどいことになったのも当然だ。
© Copyright 2025 ExpyDoc