λ式と再帰を使って連分数を計算するRubyワンライナーでπを近似する
お久しぶりです。もう定番ネタと化しているπの近似値ですが(諦)、今回は第3弾となります。
πの近似値を連分数で求める
公式
今回参考にした公式が、Wikipediaに載ってます。
wikipedia:連分数#様々な数の連分数展開
引用させていただくと、
あ、ちなみに↑の連分数なのですが、はてな記法で書くにはコツがありまして、
私はこんな感じで書いています。
<div style="text-align: center;"> [tex: \displaystyle \frac{4}{\pi} = 1+ \displaystyle \frac{1^2}{3+ \displaystyle \frac{2^2}{5+ \displaystyle \frac{3^2}{7+ \displaystyle \frac{4^2}{9+ \displaystyle \frac{5^2}{11+ \displaystyle \frac{6^2}{\ddots } } } } } } ] </div>
余談でした。
さて、問題は連分数をどうやって実装するのかですね
再帰を使う
やはり最初に思い浮かんだのは再帰でした。
イメージとしては
これがテンプレートになって、これをイテレートしていくと
という具合に求まっていきます。再帰的ですね。
さて問題の上のπの公式をRubyに落とし込むと、こんな感じに
def pi_continued_fraction(num1, num2, loopcount) return 1 if loopcount <= 0 num1 + (num2**2 / pi_continued_fraction(num1 + 2, num2 + 1, loopcount - 1)) end puts 4 / pi_continued_fraction(1.0, 1.0, 25)
三項演算子の呪い
私「n?このコードもう少し短くできるよね?」
可読性「えっ?(困惑)」
私「三項演算子をすこれよ」
def pi_continued_fraction(num1, num2, loopcount) loopcount <= 0 ? 1 : num1 + (num2**2 / pi_continued_fraction(num1 + 2, num2 + 1, loopcount - 1)) end puts 4 / pi_continued_fraction(1.0, 1.0, 25)
λ式の呪い
私「関数定義はやっぱ一行だよね」
可読性「やめとk」
ラムダ騎士団「いいぞ(食い気味)」
私「ラムダ式すこ」
pi_continued_fraction = ->(num1, num2, loopcount) { loopcount <= 0 ? 1 : num1 + (num2**2 / pi_continued_fraction.call(num1 + 2, num2 + 1, loopcount - 1)) } puts 4 / pi_continued_fraction.call(1.0, 1.0, 25)
ワンライナーの呪い
私「2行...」
可読性「日本では古来から、奇数は縁起が良いと言われてきたらしい」
私「あぁ、三重塔とか五稜郭とか三十一文字とかそうだね」
「「一行にするか」」
puts 4/(pi_continued_fraction = ->(num1, num2, loopcount) { loopcount <= 0 ? 1 : num1 + (num2**2 / pi_continued_fraction.call(num1 + 2, num2 + 1, loopcount - 1)) }).call(1.0,1.0,25)
できればπの近似値をはじき出す関数
pi()
の定義がしたいので、
最終的には
puts pi = -> { 4 / (pi_continued_fraction = ->(num1, num2, loopcount) { loopcount <= 0 ? 1 : num1 + (num2**2 / pi_continued_fraction.call(num1 + 2, num2 + 1, loopcount - 1)) }).call(1.0, 1.0, 25) }.call
となりました。
ターミナルには
> 3.141592653589793
と表示されました。だいたい25項目よりも前には小数点以下15桁は求まるみたいです。
最後に
最後まで読んでいただき、ありがとうございました。
誰か可読性ちゃんを擬人化してくれると嬉しいです。