{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/gao-su-huibonatutishu-lie-wobinenogong-shi-woshi-igodeshi-zhuang-suru/",
    "result": {"data":{"ghostPost":{"id":"Ghost__Post__60fab0573986b000013a3bd3","title":"【高速】フィボナッチ数列をビネの公式を使いGoで実装する","slug":"gao-su-huibonatutishu-lie-wobinenogong-shi-woshi-igodeshi-zhuang-suru","featured":false,"feature_image":"https://ghost.tech.anti-pattern.co.jp/content/images/2022/04/0_3BxGn-hH4T-yPdH9.jpeg","excerpt":"\n結論\nO(log (n))となり\n\n1000項目めを求めるには0.000199s\n\n10000項目めは0.000405sで求められました。\n\n完成品\nhttps://github.com/kooooohe/fibonacci/blob/master/main.g\n[https://github.com/kooooohe/fibonacci/blob/master/main.go]o\n\n\n\n通常の再帰を使った簡単な解き方\n\n\nfib_blog_1.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/17818f61bcfe287eb2709466eaccbf7f]func fib(num int) int {\n\tif num <= 1 {\n\t\treturn num\n\t}\n\treturn fib(num-2) + fib(num-1)\n}\n\n\nこれだとO(2^n)となるためかなり遅い。\n\n※メモ化については今回は割愛 ","custom_excerpt":null,"visibility":"public","created_at_pretty":"23 July, 2021","published_at_pretty":"22 August, 2020","updated_at_pretty":"21 April, 2022","created_at":"2021-07-23T21:04:39.000+09:00","published_at":"2020-08-23T00:00:00.000+09:00","updated_at":"2022-04-21T17:16:38.000+09:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"name":"Kohei Kondo","slug":"kooooohe","bio":null,"profile_image":"https://ghost.tech.anti-pattern.co.jp/content/images/2022/04/MVIMG_20180910_102813.png","twitter":"@kooooohe_","facebook":null,"website":null}],"primary_author":{"name":"Kohei Kondo","slug":"kooooohe","bio":null,"profile_image":"https://ghost.tech.anti-pattern.co.jp/content/images/2022/04/MVIMG_20180910_102813.png","twitter":"@kooooohe_","facebook":null,"website":null},"primary_tag":{"name":"fibonacci number","slug":"fibonacci-number","description":null,"feature_image":null,"meta_description":null,"meta_title":null,"visibility":"public"},"tags":[{"name":"fibonacci number","slug":"fibonacci-number","description":null,"feature_image":null,"meta_description":null,"meta_title":null,"visibility":"public"},{"name":"Go","slug":"go","description":null,"feature_image":null,"meta_description":null,"meta_title":null,"visibility":"public"},{"name":"golang","slug":"golang","description":null,"feature_image":null,"meta_description":null,"meta_title":null,"visibility":"public"},{"name":"algorithm","slug":"algorithm","description":null,"feature_image":null,"meta_description":null,"meta_title":null,"visibility":"public"}],"plaintext":"\n結論\nO(log (n))となり\n\n1000項目めを求めるには0.000199s\n\n10000項目めは0.000405sで求められました。\n\n完成品\nhttps://github.com/kooooohe/fibonacci/blob/master/main.g\n[https://github.com/kooooohe/fibonacci/blob/master/main.go]o\n\n\n\n通常の再帰を使った簡単な解き方\n\n\nfib_blog_1.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/17818f61bcfe287eb2709466eaccbf7f]func fib(num int) int {\n\tif num <= 1 {\n\t\treturn num\n\t}\n\treturn fib(num-2) + fib(num-1)\n}\n\n\nこれだとO(2^n)となるためかなり遅い。\n\n※メモ化については今回は割愛 メモ化すれば O(n)となる\n\n一般項を求める公式\n証明は漸化式を使うのだが、今回の主題ではないので割愛。\n\n> 興味ある方は: https://mathtrain.jp/fibonacci\nこれをGoで実装していく前に考えることがある。\n\n`√5`は無理数であるため、プログラムでは表現できない。\n\n丸め誤差が起きてしまい、100項目までいくと全然違う数値になってしまう。ただ今回は結果的に出てくる値が自然数になるため、それをうまく使うことにしよう。\n\nいわゆる複素数的なものを作れば良い。\n\nということで今回の無理数√5を表現するための構造体からまずは作成する。\n\nfib_blog_2.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/49864a6391696556ffecabd8fca96ee1]type fibNum struct {\n\tnum               *big.Rat\n\tnumMultipliedBySR *big.Rat\n}\n\n\nとなるためこの表現には\n\nfib_blog_3.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/ec678aa10d459a214b9eca04d2192cb1]a := big.NewRat(1, 2)\nb := big.NewRat(1, 2)\nfibNum{a, b}\n\n\n\nこれを使う。\n\n同様にしてこのビネの公式をこの構造体を使い表すと\n\nfib_blog_4.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/2704104a6cb796fd376c948fe21118c5]a := big.NewRat(1, 2)\nb := big.NewRat(1, 2)\nfibNum{a, b}\n\n\nこのようになる。\n\n各関数の実装\n乗算実装\n上記の式変形を利用して、 fibNum構造体の乗算を実装する\n\na,c= fibNum.num\n\nb,d = fibNum.numMultipliedBySR と置き換えてもらえれば良い。\n\nfib_blog_5.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/abc5d6d4c5a920248ac3be026891c6ec]\n//(a+b√5)(c+d√5) = (ac+5bd)+(ad+bc)√5\nfunc fibMul(t1, t2 fibNum) (r fibNum) {\n\t//(ac+5bd)\n\tvar r1, r2 *big.Rat\n\ttmp1 := new(big.Rat).Mul(t1.num, t2.num)\n\ttmp2 := new(big.Rat).Mul(\n\t\tnew(big.Rat).Mul(t1.numMultipliedBySR, t2.numMultipliedBySR),\n\t\tbig.NewRat(5, 1),\n\t)\n\tr1 = new(big.Rat).Add(tmp1, tmp2)\n\n\t//(ad+bc)√5\n\ttmp3 := new(big.Rat).Mul(t1.num, t2.numMultipliedBySR)\n\ttmp4 := new(big.Rat).Mul(t1.numMultipliedBySR, t2.num)\n\tr2 = new(big.Rat).Add(tmp3, tmp4)\n\n\t//(ac+5bd)+(ad+bc)√5\n\t//new(big.Rat).Add(r3, rr3)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\n\n累乗実装\nこれは作成済みのfibMul関数を流用すれば簡単である。\n\nfib_blog_6.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/3887b0ddd4cdc463b8f0520d2702ec98]func fibExp(t fibNum, n int) (r fibNum) {\n\tr := t\n\tfor i := 1; i < n; i++ {\n\t\tr = fibMul(t, r)\n\t}\n\treturn\n}\n\n\n簡単な実装はこうだが、このアルゴリズムでは\n\nO(n)の時間がかかってしまう。\n\n高速指数計算アルゴリズム\nそこで高速指数計算アルゴリズムを実装していく\n\nfib_blog_7.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/f0562f7b847dab43a2a5e5f1b274a7cb]\nfunc fibExp(t fibNum, n int) fibNum {\n\n\tr := t\n\n\t// 1\n\ta := fibNum{num: big.NewRat(1, 1), numMultipliedBySR: big.NewRat(0, 999)}\n\n\tfor n > 1 {\n\t\tif n%2 == 1 {\n\t\t\ta = fibMul(a, r)\n\t\t}\n\t\tr = fibMul(r, r)\n\t\tn = n / 2\n\t}\n\n\treturn fibMul(r, a)\n}\n\n\nすでに計算したものの2乗が使えるものは使っていこうという作戦\n\n例: 2¹⁶ = (((2²)²)²)² といった具合である。\n\nもちろんこれのみでは表現できない場合もあるが、それはaとして計算をしておいて最後に掛け合わせている。\n\nこれにより O(log(n)) まで高速化\n\n6行目は、初期値である1を表現している。\n\n減算実装\nfib_blog_7.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/3892adcc05f1fd947330cbcf9686abb6]func fibMin(t1, t2 fibNum) (r fibNum) {\n\tr1 := new(big.Rat).Add(\n\t\tt1.num,\n\t\tnew(big.Rat).Mul(t2.num, big.NewRat(-1, 1)),\n\t)\n\n\tr2 := new(big.Rat).Add(\n\t\tt1.numMultipliedBySR,\n\t\tnew(big.Rat).Mul(t2.numMultipliedBySR, big.NewRat(-1, 1)),\n\t)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\n\nこれは特に難しいことはしていないのだが、一点、\n\nmath/big pkgには減算関数はなかったため、-1倍したものを足す形で実装した。\n\n除算実装\n最後に√5で割る処理が入っているが、1/√5 = 1/5 * √5 なため。\n\nこれをfibMulに渡せば同等の処理をできるため、特に実装することはなし。\n\n計測\n1000項目目を求めるには0.000199s\n\n10000項目目は0.000405s\n\nとかなり高速に求められる。\n\n全体のコード\nfib_blog_8.goGitHub Gist: instantly share code, notes, and snippets.Gist\n262588213843476\n[https://gist.github.com/kooooohe/b6734ef092992466f4c0c3a0f44688b8]\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n)\n\ntype fibNum struct {\n\tnum               *big.Rat\n\tnumMultipliedBySR *big.Rat\n}\n\nfunc main() {\n\t//println(fib(10000))\n\tfmt.Println(calcFib(10000))\n}\n\n// (((1+√5)/2)^n - ((1-√5)/2)^n) / √5\nfunc calcFib(n int) *big.Int {\n\t// (1+√5)/2\n\ta := big.NewRat(1, 2)\n\tb := big.NewRat(1, 2)\n\tx := fibNum{a, b}\n\n\t// (1-√5)/2\n\tc := big.NewRat(1, 2)\n\td := big.NewRat(-1, 2)\n\ty := fibNum{c, d}\n\n\t// (1/√5)\n\te := big.NewRat(0, 999)\n\tf := big.NewRat(1, 5)\n\tz := fibNum{e, f}\n\n\ttmp := fibMin(fibExp(x, n), fibExp(y, n))\n\n\t// *(1/√5)\n\tr := fibMul(tmp, z)\n\treturn r.num.Num()\n\n}\n\nfunc fibExp(t fibNum, n int) fibNum {\n\n\tr := t\n\n\t// 1\n\ta := fibNum{num: big.NewRat(1, 1), numMultipliedBySR: big.NewRat(0, 999)}\n\n\tfor n > 1 {\n\t\tif n%2 == 1 {\n\t\t\ta = fibMul(a, r)\n\t\t}\n\t\tr = fibMul(r, r)\n\t\tn = n / 2\n\t}\n\n\treturn fibMul(r, a)\n}\n\n/*\nfunc fibExp(t fibNum, n int) (r fibNum) {\n\ttmp := t\n\tfor i := 1; i < n; i++ {\n\t\ttmp = fibMul(t, tmp)\n\t}\n\tr = tmp\n\treturn\n}\n*/\n\nfunc fibMin(t1, t2 fibNum) (r fibNum) {\n\tr1 := new(big.Rat).Add(\n\t\tt1.num,\n\t\tnew(big.Rat).Mul(t2.num, big.NewRat(-1, 1)),\n\t)\n\n\tr2 := new(big.Rat).Add(\n\t\tt1.numMultipliedBySR,\n\t\tnew(big.Rat).Mul(t2.numMultipliedBySR, big.NewRat(-1, 1)),\n\t)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\n//(a+b√5)(c+d√5) = (ac+5bd)+(ad+bc)√5\nfunc fibMul(t1, t2 fibNum) (r fibNum) {\n\t//(ac+5bd)\n\tvar r1, r2 *big.Rat\n\ttmp1 := new(big.Rat).Mul(t1.num, t2.num)\n\ttmp2 := new(big.Rat).Mul(\n\t\tnew(big.Rat).Mul(t1.numMultipliedBySR, t2.numMultipliedBySR),\n\t\tbig.NewRat(5, 1),\n\t)\n\tr1 = new(big.Rat).Add(tmp1, tmp2)\n\n\t//(ad+bc)√5\n\ttmp3 := new(big.Rat).Mul(t1.num, t2.numMultipliedBySR)\n\ttmp4 := new(big.Rat).Mul(t1.numMultipliedBySR, t2.num)\n\tr2 = new(big.Rat).Add(tmp3, tmp4)\n\n\t//(ac+5bd)+(ad+bc)√5\n\t//rrr := new(big.Rat).Add(r3, rr3)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\nfunc fib(num int) int {\n\tif num <= 1 {\n\t\treturn num\n\t}\n\treturn fib(num-2) + fib(num-1)\n}","html":"<h3></h3><h3 id=\"%E7%B5%90%E8%AB%96\">結論</h3><p>O(log (n))となり</p><p>1000項目めを求めるには<strong>0.000199s</strong></p><p>10000項目めは<strong>0.000405s</strong>で求められました。</p><h3 id=\"%E5%AE%8C%E6%88%90%E5%93%81\">完成品</h3><p><a href=\"https://github.com/kooooohe/fibonacci/blob/master/main.go\" rel=\"noopener nofollow\">https://github.com/kooooohe/fibonacci/blob/master/main.g</a>o</p><p></p><h3 id=\"%E9%80%9A%E5%B8%B8%E3%81%AE%E5%86%8D%E5%B8%B0%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E7%B0%A1%E5%8D%98%E3%81%AA%E8%A7%A3%E3%81%8D%E6%96%B9\">通常の再帰を使った簡単な解き方</h3><p></p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/17818f61bcfe287eb2709466eaccbf7f\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_1.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">func fib(num int) int {\n\tif num &lt;= 1 {\n\t\treturn num\n\t}\n\treturn fib(num-2) + fib(num-1)\n}\n</code></pre>\n<!--kg-card-end: markdown--><p>これだとO(2^n)となるためかなり遅い。</p><p>※メモ化については今回は割愛 メモ化すれば O(n)となる</p><h3 id=\"%E4%B8%80%E8%88%AC%E9%A0%85%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%E5%85%AC%E5%BC%8F\">一般項を求める公式</h3><figure class=\"kg-card kg-image-card\"><img src=\"https://cdn-images-1.medium.com/max/800/0*3BxGn-hH4T-yPdH9\" class=\"kg-image\" alt loading=\"lazy\"></figure><p>証明は漸化式を使うのだが、今回の主題ではないので割愛。</p><blockquote><em>興味ある方は: </em><a href=\"https://mathtrain.jp/fibonacci\" rel=\"noopener\"><em>https://mathtrain.jp/fibonacci</em></a></blockquote><p>これをGoで実装していく前に考えることがある。</p><p>`√5`は無理数であるため、プログラムでは表現できない。</p><p>丸め誤差が起きてしまい、100項目までいくと全然違う数値になってしまう。ただ今回は結果的に出てくる値が自然数になるため、それをうまく使うことにしよう。</p><p>いわゆる複素数的なものを作れば良い。</p><p>ということで今回の無理数√5を表現するための構造体からまずは作成する。</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/49864a6391696556ffecabd8fca96ee1\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_2.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">type fibNum struct {\n\tnum               *big.Rat\n\tnumMultipliedBySR *big.Rat\n}\n</code></pre>\n<!--kg-card-end: markdown--><figure class=\"kg-card kg-image-card\"><img src=\"https://cdn-images-1.medium.com/max/800/0*gWhZmE5AYGzyuFMX.png\" class=\"kg-image\" alt loading=\"lazy\"></figure><p>となるためこの表現には</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/ec678aa10d459a214b9eca04d2192cb1\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_3.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">a := big.NewRat(1, 2)\nb := big.NewRat(1, 2)\nfibNum{a, b}\n\n</code></pre>\n<!--kg-card-end: markdown--><p>これを使う。</p><p>同様にしてこのビネの公式をこの構造体を使い表すと</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/2704104a6cb796fd376c948fe21118c5\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_4.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">a := big.NewRat(1, 2)\nb := big.NewRat(1, 2)\nfibNum{a, b}\n</code></pre>\n<!--kg-card-end: markdown--><p>このようになる。</p><figure class=\"kg-card kg-image-card\"><img src=\"https://cdn-images-1.medium.com/max/800/0*3BxGn-hH4T-yPdH9\" class=\"kg-image\" alt loading=\"lazy\"></figure><h4 id=\"%E5%90%84%E9%96%A2%E6%95%B0%E3%81%AE%E5%AE%9F%E8%A3%85\">各関数の実装</h4><h4 id=\"%E4%B9%97%E7%AE%97%E5%AE%9F%E8%A3%85\">乗算実装</h4><figure class=\"kg-card kg-image-card\"><img src=\"https://cdn-images-1.medium.com/max/800/0*UKrzkTRFdyDK13Ub.png\" class=\"kg-image\" alt loading=\"lazy\"></figure><p>上記の式変形を利用して、 <code>fibNum</code>構造体の乗算を実装する</p><p>a,c= fibNum.num</p><p>b,d = fibNum.numMultipliedBySR と置き換えてもらえれば良い。</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/abc5d6d4c5a920248ac3be026891c6ec\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_5.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">\n//(a+b√5)(c+d√5) = (ac+5bd)+(ad+bc)√5\nfunc fibMul(t1, t2 fibNum) (r fibNum) {\n\t//(ac+5bd)\n\tvar r1, r2 *big.Rat\n\ttmp1 := new(big.Rat).Mul(t1.num, t2.num)\n\ttmp2 := new(big.Rat).Mul(\n\t\tnew(big.Rat).Mul(t1.numMultipliedBySR, t2.numMultipliedBySR),\n\t\tbig.NewRat(5, 1),\n\t)\n\tr1 = new(big.Rat).Add(tmp1, tmp2)\n\n\t//(ad+bc)√5\n\ttmp3 := new(big.Rat).Mul(t1.num, t2.numMultipliedBySR)\n\ttmp4 := new(big.Rat).Mul(t1.numMultipliedBySR, t2.num)\n\tr2 = new(big.Rat).Add(tmp3, tmp4)\n\n\t//(ac+5bd)+(ad+bc)√5\n\t//new(big.Rat).Add(r3, rr3)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n</code></pre>\n<!--kg-card-end: markdown--><h4 id=\"%E7%B4%AF%E4%B9%97%E5%AE%9F%E8%A3%85\">累乗実装</h4><p>これは作成済みのfibMul関数を流用すれば簡単である。</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/3887b0ddd4cdc463b8f0520d2702ec98\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_6.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">func fibExp(t fibNum, n int) (r fibNum) {\n\tr := t\n\tfor i := 1; i &lt; n; i++ {\n\t\tr = fibMul(t, r)\n\t}\n\treturn\n}\n</code></pre>\n<!--kg-card-end: markdown--><p>簡単な実装はこうだが、このアルゴリズムでは</p><p>O(n)の時間がかかってしまう。</p><h4 id=\"%E9%AB%98%E9%80%9F%E6%8C%87%E6%95%B0%E8%A8%88%E7%AE%97%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0\">高速指数計算アルゴリズム</h4><p>そこで<strong>高速指数計算アルゴリズム</strong>を実装していく</p><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/f0562f7b847dab43a2a5e5f1b274a7cb\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_7.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">\nfunc fibExp(t fibNum, n int) fibNum {\n\n\tr := t\n\n\t// 1\n\ta := fibNum{num: big.NewRat(1, 1), numMultipliedBySR: big.NewRat(0, 999)}\n\n\tfor n &gt; 1 {\n\t\tif n%2 == 1 {\n\t\t\ta = fibMul(a, r)\n\t\t}\n\t\tr = fibMul(r, r)\n\t\tn = n / 2\n\t}\n\n\treturn fibMul(r, a)\n}\n</code></pre>\n<!--kg-card-end: markdown--><p>すでに計算したものの2乗が使えるものは使っていこうという作戦</p><p>例: 2¹⁶ = (((2²)²)²)² といった具合である。</p><p>もちろんこれのみでは表現できない場合もあるが、それはaとして計算をしておいて最後に掛け合わせている。</p><p>これにより O(log(n)) まで高速化</p><p>6行目は、初期値である1を表現している。</p><h4 id=\"%E6%B8%9B%E7%AE%97%E5%AE%9F%E8%A3%85\">減算実装</h4><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/3892adcc05f1fd947330cbcf9686abb6\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_7.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">func fibMin(t1, t2 fibNum) (r fibNum) {\n\tr1 := new(big.Rat).Add(\n\t\tt1.num,\n\t\tnew(big.Rat).Mul(t2.num, big.NewRat(-1, 1)),\n\t)\n\n\tr2 := new(big.Rat).Add(\n\t\tt1.numMultipliedBySR,\n\t\tnew(big.Rat).Mul(t2.numMultipliedBySR, big.NewRat(-1, 1)),\n\t)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n</code></pre>\n<!--kg-card-end: markdown--><p>これは特に難しいことはしていないのだが、一点、</p><p>math/big pkgには減算関数はなかったため、-1倍したものを足す形で実装した。</p><h4 id=\"%E9%99%A4%E7%AE%97%E5%AE%9F%E8%A3%85\">除算実装</h4><p>最後に√5で割る処理が入っているが、1/√5 = 1/5 * √5 なため。</p><p>これをfibMulに渡せば同等の処理をできるため、特に実装することはなし。</p><h4 id=\"%E8%A8%88%E6%B8%AC\">計測</h4><p>1000項目目を求めるには0.000199s</p><p>10000項目目は0.000405s</p><p>とかなり高速に求められる。</p><figure class=\"kg-card kg-image-card kg-width-full\"><img src=\"https://cdn-images-1.medium.com/max/2560/1*E4HQ6pG1tsM2Abw4i21Wdg.png\" class=\"kg-image\" alt loading=\"lazy\"></figure><h3 id=\"%E5%85%A8%E4%BD%93%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89\">全体のコード</h3><figure class=\"kg-card kg-bookmark-card\"><a class=\"kg-bookmark-container\" href=\"https://gist.github.com/kooooohe/b6734ef092992466f4c0c3a0f44688b8\"><div class=\"kg-bookmark-content\"><div class=\"kg-bookmark-title\">fib_blog_8.go</div><div class=\"kg-bookmark-description\">GitHub Gist: instantly share code, notes, and snippets.</div><div class=\"kg-bookmark-metadata\"><img class=\"kg-bookmark-icon\" src=\"https://github.githubassets.com/favicons/favicon.svg\"><span class=\"kg-bookmark-author\">Gist</span><span class=\"kg-bookmark-publisher\">262588213843476</span></div></div><div class=\"kg-bookmark-thumbnail\"><img src=\"https://github.githubassets.com/images/modules/gists/gist-og-image.png\"></div></a></figure><!--kg-card-begin: markdown--><pre><code class=\"language-go\">\npackage main\n\nimport (\n\t&quot;fmt&quot;\n\t&quot;math/big&quot;\n)\n\ntype fibNum struct {\n\tnum               *big.Rat\n\tnumMultipliedBySR *big.Rat\n}\n\nfunc main() {\n\t//println(fib(10000))\n\tfmt.Println(calcFib(10000))\n}\n\n// (((1+√5)/2)^n - ((1-√5)/2)^n) / √5\nfunc calcFib(n int) *big.Int {\n\t// (1+√5)/2\n\ta := big.NewRat(1, 2)\n\tb := big.NewRat(1, 2)\n\tx := fibNum{a, b}\n\n\t// (1-√5)/2\n\tc := big.NewRat(1, 2)\n\td := big.NewRat(-1, 2)\n\ty := fibNum{c, d}\n\n\t// (1/√5)\n\te := big.NewRat(0, 999)\n\tf := big.NewRat(1, 5)\n\tz := fibNum{e, f}\n\n\ttmp := fibMin(fibExp(x, n), fibExp(y, n))\n\n\t// *(1/√5)\n\tr := fibMul(tmp, z)\n\treturn r.num.Num()\n\n}\n\nfunc fibExp(t fibNum, n int) fibNum {\n\n\tr := t\n\n\t// 1\n\ta := fibNum{num: big.NewRat(1, 1), numMultipliedBySR: big.NewRat(0, 999)}\n\n\tfor n &gt; 1 {\n\t\tif n%2 == 1 {\n\t\t\ta = fibMul(a, r)\n\t\t}\n\t\tr = fibMul(r, r)\n\t\tn = n / 2\n\t}\n\n\treturn fibMul(r, a)\n}\n\n/*\nfunc fibExp(t fibNum, n int) (r fibNum) {\n\ttmp := t\n\tfor i := 1; i &lt; n; i++ {\n\t\ttmp = fibMul(t, tmp)\n\t}\n\tr = tmp\n\treturn\n}\n*/\n\nfunc fibMin(t1, t2 fibNum) (r fibNum) {\n\tr1 := new(big.Rat).Add(\n\t\tt1.num,\n\t\tnew(big.Rat).Mul(t2.num, big.NewRat(-1, 1)),\n\t)\n\n\tr2 := new(big.Rat).Add(\n\t\tt1.numMultipliedBySR,\n\t\tnew(big.Rat).Mul(t2.numMultipliedBySR, big.NewRat(-1, 1)),\n\t)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\n//(a+b√5)(c+d√5) = (ac+5bd)+(ad+bc)√5\nfunc fibMul(t1, t2 fibNum) (r fibNum) {\n\t//(ac+5bd)\n\tvar r1, r2 *big.Rat\n\ttmp1 := new(big.Rat).Mul(t1.num, t2.num)\n\ttmp2 := new(big.Rat).Mul(\n\t\tnew(big.Rat).Mul(t1.numMultipliedBySR, t2.numMultipliedBySR),\n\t\tbig.NewRat(5, 1),\n\t)\n\tr1 = new(big.Rat).Add(tmp1, tmp2)\n\n\t//(ad+bc)√5\n\ttmp3 := new(big.Rat).Mul(t1.num, t2.numMultipliedBySR)\n\ttmp4 := new(big.Rat).Mul(t1.numMultipliedBySR, t2.num)\n\tr2 = new(big.Rat).Add(tmp3, tmp4)\n\n\t//(ac+5bd)+(ad+bc)√5\n\t//rrr := new(big.Rat).Add(r3, rr3)\n\n\tr.num = r1\n\tr.numMultipliedBySR = r2\n\treturn\n}\n\nfunc fib(num int) int {\n\tif num &lt;= 1 {\n\t\treturn num\n\t}\n\treturn fib(num-2) + fib(num-1)\n}\n</code></pre>\n<!--kg-card-end: markdown-->","url":"https://ghost.tech.anti-pattern.co.jp/gao-su-huibonatutishu-lie-wobinenogong-shi-woshi-igodeshi-zhuang-suru/","canonical_url":null,"uuid":"d27c67e4-8795-4a80-9196-585bd3ea550e","page":null,"codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"60fab0573986b000013a3bd3","reading_time":6}},"pageContext":{"slug":"gao-su-huibonatutishu-lie-wobinenogong-shi-woshi-igodeshi-zhuang-suru"}},
    "staticQueryHashes": ["176528973","2358152166","2561578252","2731221146","4145280475"]}